mrkeyoor.com_
Mon 21 Sept 03:57 UTC
npmDataupdated 21 Sept 2026

fast-csv review

fast-csv 5.0.7 combines the `@fast-csv/parse` and `@fast-csv/format` Node packages. Its transform streams read delimited records, write arrays or objects as CSV, remap headers, reject malformed rows, and run per-row transforms or validators without first loading the complete file. The current patch changes dependencies and development tooling rather than the parsing contract. It returns cell text as strings, supports a one-character delimiter, and depends on Node stream and filesystem behavior; our esbuild browser target could not bundle it.

Verdict

fast-csv 5.0.7 installed in 1.1 seconds as six packages using 1 MB in our sandbox, passed npm audit, and failed our browser bundle. It fits Node pipelines that must validate or format CSV records in motion; use a synchronous parser for tiny strings and a browser-oriented parser for client files.

We installed it

Lab card: what happened when we installed fast-csvScreenshot of fast-csv documentation
Install✓ · 1.1s6 packages 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 fast-csv install cleanly?

Yes. In a fresh container with an empty cache, npm install fast-csv finished in 1 seconds, leaving 6 packages and 1 MB on disk. npm audit reported no known vulnerabilities.

Can fast-csv 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 fast-csv work with both ESM and CommonJS?

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

Does fast-csv include TypeScript types?

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

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

csv-parse: Use it when you need Node stream parsing plus a synchronous API for small in-memory inputs. fast-csv 5.0.7 installed in 1.1 seconds as six packages using 1 MB in our sandbox, passed npm audit, and failed our browser bundle.

When should you not use fast-csv?

CSV work runs in a browser or edge isolate. Our browser bundle failed on Node dependencies; Papa Parse has browser and worker paths.

API stability5/5Version 5.0.7 retains the documented `parse`, `parseFile`, `parseString`, `format`, and write-helper APIs, including the existing transform and validation event model. Its May 2026 notes list dependency and toolchain updates plus a reverted TypeScript update, with no new caller migration. The parser's header and column rules remain explicit options instead of shifting defaults inside a patch.
Docs4/5The project site separates parsing from formatting and gives option types, defaults, and examples for headers, transforms, validation, delimiters, encoding, quoting, and output helpers. It clearly documents sharp edges such as `renameHeaders`, `strictColumnHandling`, and extra columns. The top-level README contributes little beyond package links, and production concerns such as backpressure, cancellation, and expensive async row transforms require Node stream knowledge outside these docs.
Maintenance4/5GitHub shows the unarchived repository pushed on August 25, 2026, with 65 open issues and pull requests. Version 5.0.7 was published on May 6 and its release notes record dependency maintenance rather than a parser redesign. Recent activity is real, but a large share is automated toolchain work, so teams should still inspect unresolved reports touching malformed input or stream behavior before relying on an edge case.
Ecosystem4/5npm recorded 15,277,397 downloads for the week ending August 24, 2026, while GitHub reports 1,788 stars. The monorepo publishes separate parse and format packages plus the combined `fast-csv` entry point, which lets an application trim an unused direction. Its Node stream design plugs into files, HTTP bodies, and database export sources, but the failed browser build excludes client-side CSV workflows from this ecosystem.

Use it if

  • A Node upload or export must process records as a stream because the entire CSV should not sit in memory.
  • Valid rows should continue while bad column counts or validation failures are routed to `data-invalid`.
  • Parsing needs header replacement, trimming, comments, row limits, or callback-based transformations in the stream.
  • One dependency should cover both CSV ingestion and CSV generation with matching Node stream conventions.
Skip it if

Setup reality

We installed fast-csv 5.0.7 without a cache in an unprivileged Node 22 Bookworm sandbox. npm completed in 1.1 seconds; six packages occupied 1 MB afterward. The package declares two direct dependencies, zero peers, and 36 KB unpacked, with an MIT license and a Node 10 minimum. npm audit reported zero known vulnerabilities at critical, high, moderate, and low severity.

The published entry point is CommonJS and has no exports map. Both require('fast-csv') and ESM import worked in our Node 22 check, and TypeScript declarations are bundled. Applications that only parse or only format can install @fast-csv/parse or @fast-csv/format instead. Our esbuild browser build failed because the code follows Node stream and filesystem paths, so do not let it cross a client bundle boundary.

Headers are the common setup trap. With headers: true, the parser consumes row 1 as field names. Passing your own header array does not consume that row unless renameHeaders: true is also set. Too many columns throw by default; discardUnmappedColumns drops extras. Too few columns can emit data-invalid when strictColumnHandling is enabled. Decide whether those rows should stop the import, enter quarantine, or continue before wiring production input.

Use pipeline() or attach an error listener because malformed quoting and stream failures are asynchronous. Callback transforms and validators preserve record order, which means one remote lookup per row can set total throughput. skipLines removes raw physical lines before header parsing, while skipRows ignores parsed records after it. For exports, wait for the destination's finish event; the formatter ending only tells you that it has stopped producing bytes.

Patterns

Parse a file as records arrive parse-file

const fs = require('node:fs')
const { parse } = require('fast-csv')

fs.createReadStream('users.csv')
  .pipe(parse({ headers: true, trim: true, ignoreEmpty: true }))
  .on('error', console.error)
  .on('data', row => console.log(row.email))
  .on('end', count => console.log({ count }))

`headers: true` uses the first row for field names. The `end` handler receives the accepted row count, not an accumulated array.

Replace the source header row rename-headers

const { parseFile } = require('fast-csv')

parseFile('users.csv', {
  headers: ['id', 'email', 'joinedAt'],
  renameHeaders: true,
}).on('data', row => console.log(row.id))

Set `renameHeaders: true` with a header array; otherwise the source's first line is emitted as ordinary data.

Keep rejected records separate validate-rows

const { parse } = require('fast-csv')

const csv = parse({ headers: true })
  .validate(row => row.email.includes('@'))
  .on('data', accept)
  .on('data-invalid', (row, number) => reject({ number, row }))
  .on('error', console.error)

input.pipe(csv)

A validator returning `false` emits `data-invalid`; a thrown exception emits `error` and ends normal processing.

Convert CSV strings into application types transform-types

const { parse } = require('fast-csv')

input.pipe(parse({ headers: true })
  .transform(row => ({
    id: Number(row.id),
    active: row.active === 'true',
    note: row.note || null,
  })))
  .on('data', save)

Every cell starts as text. Normalize an empty string before `Number()` because JavaScript converts `''` to `0`.

Collect a small CSV string parse-string

const { parseString } = require('fast-csv')

const rows = await new Promise((resolve, reject) => {
  const output = []
  parseString('id,name\n1,Ada', { headers: true })
    .on('error', reject)
    .on('data', row => output.push(row))
    .on('end', () => resolve(output))
})

`parseString` is still asynchronous and stream-based; fast-csv does not publish a synchronous parse function.

Format object rows into a file write-file

const fs = require('node:fs')
const { format } = require('fast-csv')

const output = fs.createWriteStream('users.csv')
const csv = format({ headers: true })
csv.pipe(output)
csv.write({ id: 1, email: 'ada@example.com' })
csv.write({ id: 2, email: 'alan@example.com' })
csv.end()

Wait for `finish` on the file destination before code that uploads, renames, or reports the completed output.

Pipe a database export to HTTP stream-http

const { pipeline } = require('node:stream/promises')
const { format } = require('fast-csv')

app.get('/users.csv', async (req, res) => {
  res.type('text/csv')
  res.attachment('users.csv')
  await pipeline(db.users.stream(), format({ headers: true }), res)
})

After CSV bytes reach the client, a later query error cannot be replaced with a clean JSON error response.

Generate an Excel-friendly UTF-8 file write-excel-csv

const { writeToPath } = require('fast-csv')

writeToPath('report.csv', rows, {
  headers: true,
  writeBOM: true,
  rowDelimiter: '\r\n',
  quoteColumns: true,
})

A BOM helps Excel identify UTF-8, while `quoteColumns: true` quotes every cell and increases output size.

Choose a policy for ragged input handle-ragged-rows

const { parse } = require('fast-csv')

parse({
  headers: true,
  discardUnmappedColumns: true,
  strictColumnHandling: true,
})
  .on('data', save)
  .on('data-invalid', quarantine)
  .on('error', console.error)

This combination discards extra cells and sends short records to `data-invalid`; it does not repair missing values.

Ignore a report preamble skip-preamble

const { parseFile } = require('fast-csv')

parseFile('report.csv', {
  skipLines: 3,
  headers: true,
  skipRows: 2,
  maxRows: 100,
  comment: '#',
}).on('data', consume)

`skipLines` operates on physical input before headers; `skipRows` applies later to already parsed records.

Alternatives

PackageRegistryPick it when
csv-parsenpmUse it when you need Node stream parsing plus a synchronous API for small in-memory inputs.
papaparsenpmUse it for browser files, Web Workers, or optional dynamic type conversion.
csv-parsernpmUse it for a focused Node reader when CSV writing and validation events are unnecessary.

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.