# adaltas/node-csv: a streaming CSV parser and stringifier for Node.js and the browser

> node-csv splits CSV work into four npm packages built on the Node.js transform stream API. Here is what each one does, how to install them, and where the streaming model becomes the wrong choice.

**adaltas/node-csv** — Full featured CSV parser with simple api and tested against large datasets.

- Repository: https://github.com/adaltas/node-csv
- Website: https://csv.js.org
- Stars: 4,285 · Forks: 304
- Language: JavaScript
- License: MIT
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/adaltas-node-csv

## The problem node-csv solves, and who ends up using it

CSV looks like a solved format until a field contains a comma inside quotes, a newline inside quotes, or a custom delimiter. Splitting on commas breaks on the first quoted field. Reading a multi-gigabyte export with fs.readFileSync breaks on memory before it breaks on correctness. node-csv targets both problems at once: it is a parser that understands quoting and escaping, and it is built on the native Node.js transform stream API so records can flow through without the whole file being resident.

The audience is narrower than "anyone handling CSV". The README positions the project as CSV generation, parsing, transformation and serialization for Node.js, with the packages also usable on the web. If you are writing a Node.js service that ingests exports from a data warehouse, an ETL job that rewrites a CSV between two systems, or a CLI that converts a file to JSON, you are the intended user. If you are in a spreadsheet, or in Python, or in Go, this is not your tool. The project is JavaScript, published to npm, and the repository is a Lerna monorepo rather than a single library.

## Four packages, one streaming core

The repository README lists five entries, but one of them is an umbrella. The csv package bundles four others, and each of those can be installed and used on its own:

- csv-parse converts CSV text into arrays or objects.
- csv-stringify converts records into CSV text.
- csv-generate produces CSV strings and JavaScript objects, which is what you use to build fixtures or synthetic input.
- stream-transform is a transformation framework.

All four extend the Node.js transform stream class according to the feature list. That single design decision explains most of the API surface: because they are transform streams, you can pipe them, you get backpressure for free, and you can attach them to file reads, HTTP responses or other streams. The README also states that the packages offer an optional callback and a sync API on top of the stream interface. Those three entry points exist for the same engine, which is why the same options object appears whether you call the parser synchronously or pipe into it.

The architecture has a practical consequence worth naming. Because the packages are separate, you can depend on csv-parse alone and skip the stringifier and generator. The umbrella package is convenient, not required. The README also notes that dependencies are few, and in many cases zero, which matters if you are auditing a dependency tree for a service that only needs parsing.

## Installing node-csv and parsing a first file

Installation is through npm, and the README points to csv.js.org for the full documentation and getting-started guide. The package names are exactly as they appear in the monorepo listing, so a project that only parses needs one dependency:

```bash
npm install csv-parse
```

To use the whole toolkit, install the umbrella package instead. It pulls in the parser, stringifier, generator and transform packages, which is more than a parse-only service needs:

```bash
npm install csv
```

The parser is a transform stream, so the common pattern is to create a read stream and pipe it through. The README describes the packages as supporting both ECMAScript modules and CommonJS, and the repository ships demo directories for each combination (demo/esm, demo/cjs, demo/ts-esm-node16, demo/ts-cjs-node16, demo/browser, demo/webpack), so you can match your module system against a working example rather than guessing. The README does not reproduce a full parse example inline; the getting-started page at csv.js.org is where the worked code lives, and the demo directories in this repository are runnable references for the module system you use.

The parser emits one object per data row keyed by the header names when the columns option is enabled, and arrays when it is not. The same package exposes a sync API and a callback API, so a one-off script that does not need streaming can call the parser directly on a string or buffer instead of wiring up a read stream.

## Generating and stringifying without hand-built quoting

The reverse direction is csv-stringify, which converts records into CSV text and handles the quoting rules you would otherwise write yourself. The generator, csv-generate, is the piece people overlook: the README describes it as a flexible generator of CSV string and JavaScript objects, which means you can produce test fixtures or load-test input without checking a large file into the repository. stream-transform sits between the two when the job is not a straight conversion but a per-record modification.

A realistic pipeline uses more than one. Read a file, parse it, transform each record, stringify the result, write it out. Each stage is a transform stream, so the assembly is a chain of pipes and memory stays bounded by the stream buffers rather than the file size. That is the argument for choosing this project over a parser that returns a complete array: the array approach is simpler to write and fails differently, usually by exhausting memory or by blocking the event loop while it works through a large input.

The cost of the stream model is error handling. Errors surface as stream events rather than thrown exceptions at the call site, so a pipeline needs an error listener on each stage or on the final stream. The README does not document a single consolidated error-handling recipe in the excerpt available; the documentation site is where the option and event details live.

## Where the streaming model stops being the right answer

The clearest limitation is scope. This is JavaScript for Node.js and the web. The README states Node.js support from version 8 to latest, which is a wide range, but it is still Node.js. If your pipeline is Python, Go or a database's native COPY command, node-csv has nothing to offer and you should not introduce a Node.js service just to reach it.

Second, the project is a parser and a serializer, not a data framework. It does not validate your schema, coerce types beyond what the parser options allow, or resolve encoding problems. A latin-1 export will not be fixed by choosing a different option in the excerpt the README provides; you decode the bytes before the parser sees them. Teams that expect typed output from a CSV reader are usually surprised that the parser hands back strings and leaves interpretation to the caller.

Third, the stream API is the wrong shape for small, interactive work. If you are parsing a few kilobytes inside a request handler, the sync or callback API is less code and easier to reason about, and the stream machinery adds ceremony for no benefit. The project supports both, so the mistake is not in the library but in reaching for pipes when a direct call would do.

Finally, the monorepo means version alignment is your responsibility when you install individual packages rather than the umbrella. Nothing in the repository's package.json enforces that a hand-picked csv-parse and csv-stringify stay compatible across major versions.

## How node-csv differs from fast-csv

fast-csv is the alternative most people land on, and the difference is structural rather than a matter of feature checklists. fast-csv is a single package that offers both parsing and formatting under one API. node-csv is a set of four npm packages, with csv as the umbrella, each focused on one direction of the conversion. That means node-csv asks you to decide what you need and install accordingly, while fast-csv gives you one dependency and one surface.

The second difference is the API philosophy. node-csv exposes the native Node.js transform stream as the primary interface, with the callback and sync APIs as optional conveniences layered on top. fast-csv presents its own formatting and parsing entry points first. If your codebase already thinks in streams and pipes, node-csv fits without a translation layer. If you would rather call a function that takes a string and returns rows, the fast-csv style is less friction, and node-csv's sync API is the closest equivalent.

Neither difference is a quality judgement. The repository README describes node-csv as a mature project with more than 10 years of history and full unit test coverage, and the last push was on 2026-09-23, so maintenance is current. The choice comes down to whether you want one package with a bespoke API or four packages with the platform's stream API underneath.

## Maintenance, licence and the cost of upgrading

The repository is not archived, and the last push was on 2026-09-23. It is a Lerna monorepo with npm workspaces, where packages/* and demo/* are workspace members. The root package.json is private and holds only development tooling: Lerna for versioning and publishing, ESLint with Prettier, commitlint with the conventional config, husky and lint-staged. Publishing runs through lerna publish from-git --yes, and versioning through lerna version, which is the standard fixed-version monorepo flow. In practice that means the four packages move together, and a major bump in one is likely to be a major bump in all of them.

Upgrade cost therefore depends on how you installed it. If you depend on the csv umbrella, you track one version. If you depend on individual packages, you have to keep them aligned yourself. The commitlint and conventional-commit setup suggests the changelogs are generated from commit messages, so the release notes are the place to look before a major upgrade; the excerpt retrieved here contains no release entries, so check the tags on the repository before assuming a smooth path.

The licence is MIT, stated in the README and in the LICENSE file at the repository root. MIT is permissive: it allows commercial and closed-source use, and it requires preserving the copyright notice and licence text. That is a description of the licence terms, not legal advice; if your organisation has a policy on third-party licences, route it through the people who own that policy. The project is sponsored by Adaltas, a consulting firm, and David Worms is listed as the maintainer.

## Conclusion

Adopt node-csv when you are processing CSV inside a Node.js service and you want the native transform stream API, the optional callback and sync APIs, or both ESM and CommonJS entry points. Do not adopt it for spreadsheet-style formula evaluation, encoding conversion, or work that is not JavaScript: the repository only publishes JavaScript packages for Node.js and the web, and the README documents no dependency-free path outside that. Before committing, check the Node.js version your runtime actually reports against the supported range the README states, confirm which of the four packages you need so you do not pull the csv umbrella unnecessarily, and read the option list for csv-parse on csv.js.org for the exact dialect your files use. The last push to the repository was on 2026-09-23.

## FAQ

### How do I read a CSV file in Node.js with node-csv?

Install csv-parse from npm, create a read stream for the file, and pipe it through the parser. With the columns option set to true, the parser emits one object per row keyed by the header names instead of arrays.

### What does CSV stand for?

The README treats CSV as the delimited text format the project parses, generates and stringifies, and it does not expand the acronym. The project's concern is the format's mechanics, such as quoting and escaping, not its name.

### What is better, JSON or CSV?

The README does not compare the two formats. What it does say is that csv-parse converts CSV text into arrays or objects, so JSON-shaped output is reachable from CSV input through the parser rather than being a separate concern of the project.

### Can an API return a CSV in node-csv?

The packages extend the Node.js transform stream API, so csv-stringify can be piped into an HTTP response the same way any other transform stream can. The README does not include a worked HTTP example, so the exact wiring is something to build from the stream documentation.

## Sources

- [adaltas/node-csv on GitHub](https://github.com/adaltas/node-csv)
- [Issues](https://github.com/adaltas/node-csv/issues)
- [License: MIT](https://github.com/adaltas/node-csv/blob/master/LICENSE)
- [Project website](https://csv.js.org)
- [README](https://github.com/adaltas/node-csv/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/adaltas-node-csv
