mrkeyoor.com_
Wed 23 Sept 00:32 UTC
npmDataupdated 22 Sept 2026

csv-parser review

csv-parser 3.2.1 is a Node Transform stream that reads CSV bytes and emits one object for each row. It handles quoted fields and embedded newlines, lets you supply or rewrite headers, converts values through a callback, enforces column counts, and can report the starting byte offset of every row. The package also installs a CLI that writes newline-delimited JSON. Version 3.2.1 drops columns named `__proto__`, `constructor`, or `prototype` to close a prototype-pollution path. Our browser bundle failed, matching a CommonJS, Node-stream parser rather than code intended for a web page.

Verdict

csv-parser 3.2.1 installed in 0.3 seconds as one 1 MB package with bundled types and no audit findings, but our browser bundle failed. It is a good fit for bounded Node stream ingestion; set `strict` and `maxRowBytes`, clean the encoding first, and do not depend on the broken CLI flags.

We installed it

Lab card: what happened when we installed csv-parserScreenshot of csv-parser documentation
Install✓ · 0.3s1 package on disk · 1 MB
ImportESM import works · require() works · CommonJS package
Browsern/acould not be bundled for the browser (Node-only code, most likely)
TypesTypeScript types bundled
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does csv-parser install cleanly?

Yes. In a fresh container with an empty cache, npm install csv-parser finished in 0.3s, leaving 1 package and 1 MB on disk. npm audit reported no known vulnerabilities.

Can csv-parser run in a browser?

Not directly: esbuild could not bundle it for the browser in our run, which normally means it depends on Node built-ins. Use it on the server, or find a browser-targeted alternative.

Does csv-parser work with both ESM and CommonJS?

Yes. Both import 'csv-parser' and require('csv-parser') worked in Node 22 in our run. The package is published as CommonJS.

Does csv-parser include TypeScript types?

Yes, type declarations ship inside the package, so no @types install is needed.

csv-parser or csv-parse: which should you use?

csv-parse: Choose it for sync and callback modes, casting controls, and a larger set of dialect and recovery options. csv-parser 3.2.1 installed in 0.3 seconds as one 1 MB package with bundled types and no audit findings, but our browser bundle failed.

When should you not use csv-parser?

You want a Promise returning all rows. csv-parser emits a stream, and collecting every object into an array removes its main memory advantage.

API stability4/5The package still revolves around `csv(options)` returning a Node Transform, with headers, mapping callbacks, separators, strict rows, and stream events retaining their established forms. Version 3.2 added `outputByteOffset`, which deliberately changes emitted chunks when enabled. Version 3.2.1 then removed three dangerous header names. Both changes are contained, but consumers that accept arbitrary headers or enable offsets must test the resulting object shape.
Docs3/5The README documents parsing, every option, emitted events, the command line, encoding conversion, BOM removal, and benchmark fixtures. Several statements disagree with 3.2.1: it says Node 8.16 while package.json requires Node 10, labels the return value as an array even though it is a Transform, and advertises 2 CLI switches that its current argument parser never handles. The usable material is good, but readers must check it against source.
Maintenance4/5Version 3.2.1 and the latest repository push both landed on May 7, 2026, with a focused prototype-pollution fix. GitHub shows an unarchived project with 64 open issues and pull requests, and the test corpus includes csv-spectrum cases for awkward quoting, newlines, encodings, and malformed rows. Old Travis badges and stale runtime wording remain in the README, so maintenance appears targeted at parser behavior rather than documentation cleanup.
Ecosystem5/5npm recorded 3,371,428 downloads for the week ending August 24, 2026, and GitHub reports 1,502 stars. The package plugs into built-in Node streams, includes TypeScript declarations and an NDJSON CLI, and documents companion tools for BOM removal, transcoding, and Promise collection. Both CommonJS require and ESM import worked in our sandbox, which keeps it usable across old and current Node project layouts.

Use it if

  • A large CSV must move through a Node pipeline row by row without collecting the entire table in memory.
  • The destination is already a writable stream or an async row consumer that can preserve backpressure.
  • Headers need renaming or removal and a few cells need conversion during parsing.
  • Imports need byte offsets so a rejected record can be tied back to its location in the original file.
Skip it if

Setup reality

We installed csv-parser 3.2.1 in 0.3 seconds in a clean Node 22 Bookworm sandbox. The result was one package and 1 MB on disk; the package is 48 KB unpacked and has 0 direct and 0 peer dependencies. npm audit reported 0 known vulnerabilities. require() and ESM import both worked, even though the package is CommonJS and has no exports map. It includes TypeScript declarations, carries an MIT license, and declares Node 10 or newer.

There are no native builds, credentials, or config files. Input cleanup belongs in the stream before csv(): remove a UTF-8 BOM, and transcode non-UTF-8 files with a tool such as iconv-lite. Cells remain strings unless mapValues converts them. If you supply headers for a file that already has a header line, also set skipLines: 1 or that line becomes ordinary data.

Set strict: true when every row must match the header count. With the default false setting, extra cells receive names such as _10, while missing middle cells can shift values under the wrong property. Cap maxRowBytes for uploads because its default is Number.MAX_SAFE_INTEGER. Version 3.2.1 silently removes three dangerous property names, so a legitimate column called constructor will also disappear.

Consume the Transform with pipeline(), a writable stream, or for await and handle errors from both the source and parser. Awaiting each async-iterator row preserves backpressure; attaching data and launching unbounded promises does not. Our browser build failed, which is consistent with Node stream use. The CLI writes one JSON object per line, and its --strict and --remove help entries should not be trusted in this release.

Patterns

Read a CSV file one row at a time stream-file-rows

const fs = require('node:fs');
const csv = require('csv-parser');

fs.createReadStream('data.csv')
  .pipe(csv())
  .on('data', (row) => console.log(row))
  .on('error', (error) => console.error(error))
  .on('end', () => console.log('done'));

The first physical row supplies property names and is not emitted. Every later cell is a string unless you map it.

Process rows through an async iterator await-each-row

const fs = require('node:fs');
const csv = require('csv-parser');

const rows = fs.createReadStream('data.csv').pipe(csv());
for await (const row of rows) {
  await saveRow(row);
}

Awaiting inside the loop limits work to one row at a time and lets stream backpressure reach the file reader. Parser or file errors reject the loop.

Assign numeric keys to headerless input parse-headerless-file

fs.createReadStream('rows.csv')
  .pipe(csv({ headers: false }))
  .on('data', (row) => {
    console.log(row['0'], row['1']);
  });

With `headers: false`, the first row is data and keys are column indexes. The implementation also disables strict checking in this mode, so validate width yourself.

Supply fixed names and skip the original header override-headers

const parser = csv({
  headers: ['name', 'age'],
  skipLines: 1,
  strict: true,
});

fs.createReadStream('people.csv').pipe(parser);

Providing names does not consume the file's own header line. `skipLines: 1` prevents those labels from appearing as the first record.

Normalize names and remove one column map-header-names

const parser = csv({
  mapHeaders: ({ header }) => {
    const name = header.trim().toLowerCase();
    return name === 'internal_notes' ? null : name;
  },
});

Returning null removes the whole column. Version 3.2.1 also discards `__proto__`, `constructor`, and `prototype` after header mapping.

Convert selected cells during parsing cast-cell-values

const parser = csv({
  mapValues: ({ header, value }) => {
    if (header === 'age') return Number(value);
    if (header === 'active') return value === 'true';
    return value;
  },
});

`Number('')` becomes 0 and malformed numeric text becomes NaN. Check empty and invalid cells before conversion when they need different outcomes.

Stop malformed or oversized upload rows bound-upload-rows

const { pipeline } = require('node:stream');
const parser = csv({
  strict: true,
  maxRowBytes: 1024 * 1024,
});

pipeline(
  fs.createReadStream('upload.csv'),
  parser,
  destination,
  (error) => { if (error) reportImportFailure(error); }
);

The 1 MiB cap here replaces a default of `Number.MAX_SAFE_INTEGER`. Strict mode checks column count, not cell types or required fields.

Use a tab as the field separator read-tsv

fs.createReadStream('data.tsv')
  .pipe(csv({ separator: '\t' }))
  .on('data', processRow);

The parser uses the first byte of the separator. Multi-character and multibyte Unicode separators are outside this API.

Skip two preamble lines and hash comments ignore-preamble

const parser = csv({
  skipLines: 2,
  skipComments: '#',
});

fs.createReadStream('export.csv').pipe(parser);

Comment syntax is an input convention, not part of CSV itself. A line is skipped only when the configured marker appears at its start.

Strip a UTF-8 BOM before parsing headers remove-bom

const stripBom = require('strip-bom-stream');

fs.createReadStream('excel-export.csv')
  .pipe(stripBom())
  .pipe(csv())
  .on('data', processRow);

csv-parser leaves the BOM untouched. Without a stripping transform, the invisible bytes become part of the first header name.

Emit each row with its source position record-byte-offset

fs.createReadStream('data.csv')
  .pipe(csv({ outputByteOffset: true }))
  .on('data', ({ byteOffset, row }) => {
    indexRow(byteOffset, row);
  });

This option changes the chunk from a plain row to `{ byteOffset, row }`. Update every downstream transform and its TypeScript type.

Convert a file to newline-delimited JSON write-ndjson

npx csv-parser input.csv > output.ndjson
# standard input also works
node produce-csv.js | npx csv-parser -s ';' > output.ndjson

The command writes one JSON object per line rather than one JSON array. Version 3.2.1 lists `--strict` and `--remove` in help but does not implement them.

Alternatives

PackageRegistryPick it when
csv-parsenpmChoose it for sync and callback modes, casting controls, and a larger set of dialect and recovery options.
@fast-csv/parsenpmChoose it for typed stream parsing with row validation and transformation hooks built into the parser.
papaparsenpmChoose it for browser files, delimiter detection, workers, or a parser shared between frontend and Node code.
neat-csvnpmChoose it for small files when one Promise containing every row is the simpler contract.

More data guides

numpy · fsspec · pandas · sqlalchemy · pyarrow · lxml · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.