Writing files with Node

By

Learn how to write files in Node.js with the fs module, using writeFile() and writeFileSync(), the promises API, file flags, appendFile(), and streams.

~~~

The easiest way to write to files in Node.js is to use the fs.writeFile() API.

Example:

const fs = require('node:fs')

const content = 'Some content!'

fs.writeFile('/Users/flavio/test.txt', content, (err) => {
  if (err) {
    console.error(err)
    return
  }
  //file written successfully
})

The node: prefix makes it clear that fs is a module built into Node. require('fs') without the prefix loads the same module.

Alternatively, you can use the synchronous version fs.writeFileSync():

const fs = require('node:fs')

const content = 'Some content!'

try {
  fs.writeFileSync('/Users/flavio/test.txt', content)
  //file written successfully
} catch (err) {
  console.error(err)
}

By default, this API will replace the contents of the file if it already exists.

You can change that by passing a flag:

fs.writeFile('/Users/flavio/test.txt', content, { flag: 'a+' }, (err) => {})

The flags you’ll likely use are:

(you can find more flags at https://nodejs.org/api/fs.html#fs_file_system_flags)

The promises version

The node:fs/promises module gives you the same functions, but they return promises. You can await them instead of passing a callback:

import fs from 'node:fs/promises'

const content = 'Some content!'

try {
  await fs.writeFile('/Users/flavio/test.txt', content)
} catch (err) {
  console.error(err)
}

Top-level await works in ES modules. In CommonJS, use require('node:fs/promises') and wrap the call in an async function.

The options are the same, so { flag: 'a+' } works here too.

Append to a file

A handy way to add content to the end of a file is fs.appendFile() (and its fs.appendFileSync() counterpart):

const content = 'Some content!'

fs.appendFile('file.log', content, (err) => {
  if (err) {
    console.error(err)
    return
  }
  //done!
})

With promises:

import fs from 'node:fs/promises'

await fs.appendFile('file.log', 'Some content!\n')

Using streams

All those methods write the full content to the file before returning the control back to your program (in the async version, this means executing the callback).

When the content is big, or you produce it a bit at a time, a better option is to write it using streams.

A write stream lets you send the content in pieces. Node writes each piece to the file in the background, so you don’t have to put the whole content in one string first.

You create one with fs.createWriteStream(), call write() for each chunk, and call end() when you’re done:

const fs = require('node:fs')

const stream = fs.createWriteStream('/Users/flavio/test.txt')

stream.write('First line\n')
stream.write('Second line\n')
stream.end('Last line\n')

stream.on('finish', () => {
  console.log('File written')
})

stream.on('error', (err) => {
  console.error(err)
})

end() accepts one last chunk, then closes the stream. The finish event fires once all the data has been flushed to the file.

Listen for error too. It fires, for example, when the folder doesn’t exist or you don’t have permission to write there.

Like writeFile(), this replaces the file content. To append, pass the a flag. Here the option is called flags:

const stream = fs.createWriteStream('/Users/flavio/app.log', { flags: 'a' })

Streams are great when you produce the content over time. Here we write 100,000 lines, one at a time, without building a giant string:

const fs = require('node:fs')

const stream = fs.createWriteStream('/Users/flavio/numbers.txt')

for (let i = 1; i <= 100000; i++) {
  stream.write(`Line number ${i}\n`)
}

stream.end()

stream.on('finish', () => {
  console.log('Done writing numbers.txt')
})

When write() returns false, the stream’s internal buffer is full. For a file of this size you can ignore it. With really big or endless data, stop and wait for the drain event before writing more. My Node.js streams guide explains how, and covers pipeline() too.

So when do you pick one or the other?

For a config file, a JSON result or any content you already have in a variable, writeFile() is simpler. Use a stream when the content is large, or when you keep writing to the same file over time, like a log.

Tagged: Node.js · All topics

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

~~~

Related posts about node: