csv-parse の使い方

CSV parsing implementing the Node.js `stream.Transform` API

v6.2.1/週MITユーティリティ
AI生成コンテンツ

この記事はAIによって生成されました。内容の正確性は保証されません。最新の情報は公式ドキュメントをご確認ください。

csv-parse の使い方 — Node.js向けCSVパーサーの決定版

一言でいうと

csv-parse は、CSV テキストを配列やオブジェクトに変換する Node.js 向けパーサーです。Node.js の stream.Transform API を実装しており、小さなファイルから大規模データセットまで柔軟に対応できます。

どんな時に使う?

  • CSVファイルのインポート処理 — ユーザーがアップロードしたCSVファイルをパースしてデータベースに投入する
  • 大容量CSVのストリーム処理 — 数GB級のCSVファイルをメモリを圧迫せずに1行ずつ処理する
  • 外部システムとのデータ連携 — 他システムから受け取ったCSV/TSVデータをアプリケーション内のオブジェクトに変換する

インストール

# npm
npm install csv-parse

# yarn
yarn add csv-parse

# pnpm
pnpm add csv-parse

CSV生成(stringify)や変換(transform)も必要な場合は、npm install csv で関連パッケージを一括インストールできます。

基本的な使い方

csv-parse には主に4つのAPIフレーバーがあります。最もシンプルな Sync API と、実務で頻出する Callback API を紹介します。

Sync API(同期処理)

import { parse } from "csv-parse/sync";

const input = `name,age,city
Alice,30,Tokyo
Bob,25,Osaka`;

const records: Record<string, string>[] = parse(input, {
  columns: true,       // ヘッダー行をキーとしてオブジェクトに変換
  skip_empty_lines: true,
});

console.log(records);
// [
//   { name: 'Alice', age: '30', city: 'Tokyo' },
//   { name: 'Bob', age: '25', city: 'Osaka' }
// ]

注意: Sync API はデータ全体をメモリに載せるため、大容量ファイルには向きません。

Callback API(コールバック)

import { parse } from "csv-parse";

const input = `name,age,city
Alice,30,Tokyo
Bob,25,Osaka`;

parse(input, { columns: true }, (err, records: Record<string, string>[]) => {
  if (err) {
    console.error(err);
    return;
  }
  console.log(records);
});

Stream API(大容量ファイル向け)

import fs from "node:fs";
import { parse } from "csv-parse";

const parser = fs
  .createReadStream("/path/to/large-file.csv")
  .pipe(parse({ columns: true }));

for await (const record of parser) {
  // 1行ずつ処理(メモリ効率が良い)
  console.log(record);
}

よく使うAPI・オプション

1. columns — ヘッダー行をキーにしてオブジェクト化

import { parse } from "csv-parse/sync";

const input = `id,name,email
1,Alice,alice@example.com
2,Bob,bob@example.com`;

// columns: true でヘッダー行を自動的にキーとして使用
const records = parse(input, { columns: true });
// => [{ id: '1', name: 'Alice', email: 'alice@example.com' }, ...]

// カスタムカラム名を指定することも可能
const records2 = parse(input, {
  columns: ["user_id", "user_name", "user_email"],
  from_line: 2, // 元のヘッダー行をスキップ
});
// => [{ user_id: '1', user_name: 'Alice', user_email: 'alice@example.com' }, ...]

2. delimiter — 区切り文字の変更(TSV対応など)

import { parse } from "csv-parse/sync";

// タブ区切り(TSV)
const tsv = `name\tage\tcity
Alice\t30\tTokyo`;

const records = parse(tsv, {
  columns: true,
  delimiter: "\t",
});
// => [{ name: 'Alice', age: '30', city: 'Tokyo' }]

3. cast — 型変換

import { parse } from "csv-parse/sync";

const input = `name,age,active
Alice,30,true
Bob,25,false`;

const records = parse(input, {
  columns: true,
  cast: (value, context) => {
    // 数値カラムを number に変換
    if (context.column === "age") {
      return parseInt(value, 10);
    }
    // boolean カラムを boolean に変換
    if (context.column === "active") {
      return value === "true";
    }
    return value;
  },
});

console.log(records);
// [
//   { name: 'Alice', age: 30, active: true },
//   { name: 'Bob', age: 25, active: false }
// ]

4. skip_empty_lines / skip_records_with_error — 不正行のスキップ

import { parse } from "csv-parse/sync";

const input = `name,age
Alice,30

Bob,25
Charlie,invalid`;

const records = parse(input, {
  columns: true,
  skip_empty_lines: true,          // 空行をスキップ
  skip_records_with_error: true,   // パースエラーの行をスキップ
});

5. on_record — レコード単位のフィルタリング・変換

import { parse } from "csv-parse/sync";

const input = `name,age,city
Alice,30,Tokyo
Bob,17,Osaka
Charlie,45,Nagoya`;

const records = parse(input, {
  columns: true,
  cast: (value, context) => {
    if (context.column === "age") return parseInt(value, 10);
    return value;
  },
  on_record: (record) => {
    // 18歳未満を除外(undefinedを返すとスキップ)
    if (record.age < 18) return undefined;
    // フィールドを追加して返す
    return { ...record, processed: true };
  },
});

console.log(records);
// [
//   { name: 'Alice', age: 30, city: 'Tokyo', processed: true },
//   { name: 'Charlie', age: 45, city: 'Nagoya', processed: true }
// ]

類似パッケージとの比較

特徴csv-parsepapaparsefast-csv
ストリーム対応✅ Node.js Transform Stream✅(Node.js版)
ブラウザ対応✅(メイン用途)
Sync API
TypeScript型定義✅ 同梱@types/papaparse✅ 同梱
外部依存001(@fast-csv/parse
大規模データ◎ 設計思想として重視
学習コスト低〜中低〜中

選定の目安:

  • Node.js バックエンド中心csv-parse(安定性・実績・エコシステム)
  • ブラウザ中心papaparse(ブラウザファーストの設計)
  • パース&生成を一体でfast-csv(parse/format が統合)

注意点・Tips

1. Sync API と Stream API のインポートパスが異なる

// ❌ 間違い:sync を使いたいのに通常のパスからインポート
import { parse } from "csv-parse";

// ✅ 正しい:sync 版は専用サブパスからインポート
import { parse } from "csv-parse/sync";

2. デフォルトではすべての値が string になる

columns: true を指定しても、値はすべて文字列です。数値や真偽値が必要な場合は cast オプションを明示的に設定してください。

3. BOM(Byte Order Mark)付きUTF-8の対処

Excel で保存した CSV は BOM 付きになることがあります。bom: true を指定すると自動除去されます。

const records = parse(input, {
  columns: true,
  bom: true, // BOM を自動除去
});

4. 大容量ファイルは必ず Stream API を使う

Sync API や Callback API はデータ全体をメモリに保持します。数十MB以上のファイルを扱う場合は、Stream API(for await...of または pipe)を使いましょう。

5. info プロパティでパース状況を確認できる

import { parse } from "csv-parse";

const parser = parse({ columns: true });
parser.on("end", () => {
  console.log(parser.info);
  // { bytes: 1024, columns: true, comment_lines: 0,
  //   empty_lines: 0, invalid_field_length: 0,
  //   lines: 100, records: 99 }
});

デバッグやログ出力に便利です。

まとめ

csv-parse は、2010年から開発が続く Node.js 向け CSV パーサーの定番ライブラリです。Sync / Callback / Stream と3つの API スタイルを備え、小規模なスクリプトから大規模データパイプラインまで同じライブラリで対応できます。外部依存ゼロ・TypeScript 型定義同梱という点も、プロダクション環境での採用を後押しする安心材料です。