You can use the fs module to read and write files in Node.js. The fs module is a built-in module in Node.js that provides both asynchronous and synchronous functions to read, write, and watch files.

Read Data From Files

The simplest way to read a file in Node.js is to use the fs.readFile() method by passing the file path, encoding, and a callback function.

It asynchronously reads the entire contents of the file and calls the callback function with the file data:

const fs = require('fs')

fs.readFile('file.txt', 'utf-8', (err, data) => {
  if (err) {
    throw err
  }
  console.log(data)
})

Alternatively, you can use fs.readFileSync() to read the file synchronously:

const fs = require('fs')

try {
  const data = fs.readFileSync('file.txt', 'utf-8')
  console.log(data)
} catch (err) {
  console.error(err)
}

Note: If you skip the encoding parameter, a raw buffer is returned. Otherwise, a string is returned.

You can also use the promise-based fsPromises.readFile() method to read the file:

const fsPromises = require('fs/promises')

const readFileAsync = async () => {
  try {
    const data = await fsPromises.readFile('file.txt', 'utf-8')
    console.log(data)
  } catch (err) {
    console.error(err)
  }
}

readFileAsync()

All the above three functions read the complete file contents in memory before calling the callback function and returning data.

This means that if you are reading a large file, it might have an impact on your memory consumption and execution of the program.

For large files, it is better to use streams for reading the contents of a file.

Write Data To Files

The easiest way to write data to files in Node.js is using the fs.writeFile() method.

This method takes three parameters: the file path, the data to write, and a callback function, and writes the data asynchronously:

const fs = require('fs')

const data = 'This is the new content of the file.'

fs.writeFile('file.txt', data, err => {
  if (err) {
    throw err
  }
  console.log('File is written successfully.')
})

Alternatively, you could use the fs.writeFileSync() to write the file synchronously:

const fs = require('fs')

const data = 'This is the new content of the file.'

try {
  fs.writeFileSync('file.txt', data)
  console.log('File is written successfully.')
} catch (error) {
  console.error(err)
}

You can also use the promise-based fsPromises.writeFile() method to write the file:

const fsPromises = require('fs/promises')

const writeFileAsync = async () => {
  try {
    const data = 'This is the new content of the file.'
    await fsPromises.writeFile('file.txt', data)

    console.log('File is written successfully.')
  } catch (err) {
    console.error(err)
  }
}

writeFileAsync()

By default, the above methods override the file contents if it already exists. To append data to the file, you should pass a flag as the 3rd parameter:

const fs = require('fs')

const data = 'Append this data at the end of the file.'

fs.writeFile('file.txt', data, { flag: 'a+' }, err => {
  if (err) {
    throw err
  }
  console.log('File is updated.')
})

Some of the flag options you can use:

  • r — Open the file in read-only mode. An exception is thrown if the file does not exist.
  • r+ — Open the file for reading and writing. If the file does not exist, an exception is thrown.
  • w — Open the file in write-only mode. The file is created (only if does not already exist) or truncated (if exists).
  • w+ — Open the file for reading and writing, placing the stream at the start of the file. The file is created if doesn't exist.
  • a — Open the file for appending, positioning the stream at the end of the file. The file is created if doesn't exist.
  • a+ — Open the file for reading and appending, putting the stream at the end of the file. The file is created if it does not exist.

All the above methods continue writing to the file until the complete contents have been written before returning the control back to your program.

If you are writing a lot of data, it might impact your application performance. In this case, a better approach would be to use a stream for writing to large files.

Append Data To Files

Apart from flags, the fs module also provides fs.appendFile() (and fs.appendFileSync() for synchronous) method that asynchronously append data to the file, creating the file if it does not yet exist:

const fs = require('fs')

const data = 'Some data to append'

fs.appendFile('file.txt', data, err => {
  if (err) {
    throw err
  }
  console.log('File is updated.')
})

Error Handling

If there is a runtime error while reading or writing to a file, the callback method is called with an Error object as the first argument.

The simplest way to handle runtime errors is to throw them as Node.js exceptions like above. But this will crash the application and is therefore not recommended except in cases where you have no other choice:

const fs = require('fs')

fs.readFile('404.txt', 'utf-8', (err, data) => {
  if (err) {
    console.error(err)
    // log the error here
  }
  console.log(data)
})

If you execute the above code, you will see the following output:

{ [Error: ENOENT: no such file or directory, open '404.txt'] 
    errno: -2, 
    code: 'ENOENT', 
    syscall: 'open', 
    path: '404.txt' }
undefined

Further Reading

If you enjoyed reading this article, you might also like some of my other articles:

✌️ Like this article? Follow me on Twitter and LinkedIn. You can also subscribe to RSS Feed.