How to write a CSV file with Node.js

By

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.

Tagged: Node.js · All topics

Want me to talk about your product? You can sponsor this site.

~~~

Related posts about node: