How to write a CSV file with Node.js
By Flavio Copes
Learn how to write a CSV file with Node.js using csv-stringify: turn an array of objects into a file, append rows, and get the CSV as a string.
A solid way to write an array of objects to a CSV file with Node.js is csv-stringify. You give it the rows, it builds the CSV text, and you write that to disk with the usual fs helpers.
I used to reach for objects-to-csv for one-shot exports. That package has not been updated in years. For new code, pick a maintained library instead. csv-stringify is simple for small exports. If you stream huge tables, fast-csv or the streaming API of csv-stringify fits better (see also Node.js streams).
Install it using:
npm install csv-stringify
then import the sync helper:
import { stringify } from 'csv-stringify/sync'
import { writeFile } from 'node:fs/promises'
When you have an array of objects ready, stringify it with a header row and write the file:
const people = [
{ name: 'Flavio', age: 37 },
{ name: 'Roger', age: 8 }
]
const csv = stringify(people, { header: true })
await writeFile('./people.csv', csv)
stringify() from csv-stringify/sync returns the CSV string right away. writeFile() returns a promise, and I used await on it, so you need to call this inside an async function.
Here’s a complete example you can run:
import { stringify } from 'csv-stringify/sync'
import { writeFile } from 'node:fs/promises'
const people = [
{ name: 'Flavio', age: 37 },
{ name: 'Roger', age: 8 }
]
async function saveCsv() {
const csv = stringify(people, { header: true })
await writeFile('./people.csv', csv)
}
saveCsv()
The resulting people.csv file contains:
name,age
Flavio,37
Roger,8
The column names in the CSV come from the object properties. With header: true, csv-stringify uses the keys of the first record unless you pass an explicit columns list.
How are the columns picked?
Be careful here: without columns, the header comes from the first object in the array. If a later object has an extra property, that value is silently dropped. You get no error and no warning.
const people = [
{ name: 'Flavio', age: 37 },
{ name: 'Roger', age: 8, city: 'Milan' }
]
Writing this with header: true alone gives you only the name and age columns. city disappears.
The fix is the columns option, which lists every key you want, in a fixed order:
const csv = stringify(people, {
header: true,
columns: ['name', 'age', 'city']
})
await writeFile('./people.csv', csv)
Now the file has a city column, left empty for the rows that don’t have that property.
How do you append rows?
writeFile() overwrites the file. To append, stringify the new rows without a header and use appendFile():
import { appendFile } from 'node:fs/promises'
const more = stringify([{ name: 'Sara', age: 12 }], {
header: false,
columns: ['name', 'age']
})
await appendFile('./people.csv', more)
Use the same columns list as the original file so the fields stay aligned. The header row stays at the top from the first write.
Getting the CSV as a string
Sometimes you don’t want a file at all. Maybe you’re sending the CSV as an HTTP response. In that case, keep the string from stringify():
const output = stringify(people, { header: true })
You get back the same content you would write to disk, header included.
If you need the other direction, see how to read a CSV file with Node.js. And if you’re starting from JSON in the browser, I built a free JSON ↔ CSV converter that handles both directions.
Want me to talk about your product? You can sponsor this site.
Related posts about node: