Why Streaming Beats readFileSync
Small CSVs are easy—read the whole file and parse once. Real workloads are not always small. Streaming lets Node.js process CSVs that would otherwise exhaust memory, and it keeps the event loop free for other tasks.
Choose sync for scripts under a few megabytes. Choose streaming for anything you might run in a server or long-running job.
Pick a Library
All three are solid. Pick based on how the rest of your stack looks.
| Library | Strengths | Fit |
|---|---|---|
| csv-parse | Rich options, streaming and sync | General-purpose Node |
| fast-csv | Ergonomic API, streams | TypeScript-friendly pipelines |
| papaparse | Same API as browser Papa Parse | Isomorphic (browser + Node) |
Step-by-Step: Streaming with csv-parse
The canonical streaming pattern in Node.js.
import fs from "node:fs";
import { parse } from "csv-parse";
const parser = parse({
columns: true,
skip_empty_lines: true,
bom: true,
});
fs.createReadStream("orders.csv")
.pipe(parser)
.on("data", (row) => {
// process one row
})
.on("end", () => console.log("done"))
.on("error", (err) => console.error(err));Sync parse for small files
Great for CLI utilities and tests.
import fs from "node:fs";
import { parse } from "csv-parse/sync";
const text = fs.readFileSync("small.csv", "utf8");
const rows = parse(text, { columns: true, skip_empty_lines: true, bom: true });
console.log(rows[0]);Transform pipeline
Combine with node:stream to filter or map.
import { pipeline } from "node:stream/promises";
import { Transform } from "node:stream";
await pipeline(
fs.createReadStream("orders.csv"),
parse({ columns: true, bom: true }),
new Transform({
objectMode: true,
transform(row, _enc, cb) {
if (row.status === "paid") this.push(row);
cb();
},
}),
async function* (source) {
for await (const row of source) yield JSON.stringify(row) + "\n";
},
fs.createWriteStream("paid.ndjson"),
);Writing CSV in Node.js
csv-stringify is the mirror of csv-parse.
import fs from "node:fs";
import { stringify } from "csv-stringify";
const stringifier = stringify({ header: true });
stringifier.pipe(fs.createWriteStream("out.csv"));
stringifier.write({ id: 1, email: "ada@example.com" });
stringifier.write({ id: 2, email: "grace@example.com" });
stringifier.end();Encoding, BOM, and Delimiters
Same rules as everywhere else, but easy to forget in a server.
| Concern | Recommendation |
|---|---|
| Encoding | UTF-8 for new files; decode legacy explicitly |
| BOM | Enable bom: true so headers parse cleanly |
| Delimiter | Set delimiter explicitly for non-comma CSV |
| Nulls | Decide empty vs null and stick with it |
Real-World Examples
Common shapes of Node.js CSV work.
Nightly ETL
A cron job streams a large CSV, filters status = paid, writes NDJSON to S3.
API upload endpoint
An HTTP endpoint accepts a CSV upload, streams parsing, validates, and returns JSON errors row by row.
Data migration
A one-off script converts a legacy CSV to a new schema by mapping headers in a streaming Transform.
Common Mistakes
Avoid these to keep production stable.
- readFileSync on huge files, running out of memory.
- Not enabling bom, so "\uFEFForder_id" appears as a header key.
- Assuming every row has every column.
- Blocking the event loop with sync parsing in a server.
- Missing error handlers on streams.
Best Practices
A little discipline scales.
- Prefer streaming for anything user-triggered or scheduled.
- Handle errors with .on("error") and pipeline().
- Enable bom for CSVs that may come from Excel.
- Log row counts before and after transforms.
- Validate required columns early and bail with a clear message.
Why Use Convert CSV Online?
Sometimes the fastest debug is a browser preview. Convert CSV Online is free, browser-based, and needs no account for everyday conversions. Preview the CSV in the Online CSV Editor before wiring up your Node.js pipeline. Client-side workflows run on Windows, macOS, and Linux browsers.
Confirm structure first
Open the file online, verify delimiter and encoding, then build your parser knowing what to expect.
Conclusion
Node.js parses CSV well with the right library and streaming pattern. Choose csv-parse or fast-csv, handle errors, and enable BOM support for files from Excel.
FAQ
How do I parse CSV in Node.js?
Install a CSV library (csv-parse, fast-csv, or papaparse), then stream a file into the parser and consume rows in a data handler.
What is the best CSV library for Node.js?
csv-parse for general-purpose work, fast-csv for ergonomic TypeScript pipelines, and papaparse when you want the same API across browser and Node.
How do I handle a huge CSV in Node?
Use fs.createReadStream and pipe into a streaming parser. Avoid readFileSync for large files.
How do I handle the UTF-8 BOM?
Enable the BOM option on your parser (bom: true) so the first header does not get a stray character.
How do I write CSV in Node.js?
Use csv-stringify (paired with csv-parse) or fast-csv’s writer to stream rows into a file with headers.
How do I set a non-comma delimiter?
Pass delimiter (e.g., ";" or "\t") in your parser options.
References
Convert your CSV in the browser
Preview, clean, and convert CSV files free with Convert CSV Online—no installation and no account required for everyday conversions.