Joseph Mawa A very passionate open source contributor and technical writer

Reading and writing JSON files in Node.js: A complete tutorial

9 min read 2662

Introduction to JSON

JavaScript Object Notation, referred to as JSON in short, is one of the most popular formats for data storage and data interchange over the internet. The simplicity of the JSON syntax makes it very easy for humans and machines to read and write.

Despite its name, the use of the JSON data format is not limited to JavaScript. Most programming languages implement data structures that you can easily convert to JSON and vice versa.

JavaScript, and therefore the Node.js runtime environment, is no exception. More often than not, this JSON data needs to be read from or written to a file for persistence. The Node runtime environment has the built-in fs module specifically for working with files.

This article is a comprehensive guide on how to use the built-in fs module to read and write data in JSON format. We shall also look at some third party npm packages that simplify working with data in the JSON format.

Serializing and deserializing JSON

Serialization is the process of modifying an object or data structure to a format that is easy to store or transfer over the internet. You can recover the serialized data by applying the reverse process.

Deserialization refers to transforming the serialized data structure to its original format.

You will almost always need to serialize JSON or JavaScript object to a JSON string in Node. You can do so with the JSON.stringify method before writing it to a storage device or transmitting it over the internet:

const config = { ip: '1234.22.11', port: 3000};
console.log(JSON.stringify(config));

On the other hand, after reading the JSON file, you will need to deserialize the JSON string to a plain JavaScript object using the JSON.parse method before accessing or manipulating the data:

const config = JSON.stringify({ ip: '1234.22.11', port: 3000});
console.log(JSON.parse(config));

JSON.stringify and JSON.parse are globally available methods in Node. You don’t need to install or require before using.

Introduction to the fs module

Because the fs module is built in, you don’t need to install it. It provides functions that you can use to read and write data in JSON format, and much more.

We made a custom demo for .
No really. Click here to check it out.

Each function exposed by the fs module has the synchronous, callback, and promise-based form. The synchronous and callback variants of a method are accessible from the synchronous and callback API. The promise-based variant of a function is accessible from the promise-based API.

Synchronous API

The synchronous methods of the built-in fs module block the event loop and further execution of the remaining code until the operation has succeeded or failed. More often than not, blocking the event loop is not something you want to do.

The names of all synchronous functions end with the Sync characters. For example, writeFileSync and readFileSync are both synchronous functions.

You can access the synchronous API by requiring fs:

const fs = require('fs');

// Blocks the event loop
fs.readFileSync(path, options);

Callback API

Unlike the synchronous methods that block the event loop, the corresponding methods of the callback API are asynchronous. You’ll pass a callback function to the method as the last argument.

The callback function is invoked with an Error object as the first argument if an error occurs. The remainder of the arguments to the callback function depends upon the fs method.

You can also access the methods of the callback API by requiring fs like the synchronous API:

const fs = require('fs');

fs.readFile(path, options, callback);

Promise-based API

The promise-based API is asynchronous, like the callback API. It returns a promise, which you can manage via promise chaining or async-await.

You can access the promise-based API by requiring fs/promises:

const fs = require('fs/promises');

fs.readFile(path)
  .then((data) => {
    // Do something with the data
  })
  .catch((error) => {
    // Do something if error 
  });

We used the commonJS syntax for accessing the modules in the code snippets above. We shall be using the commonJS syntax throughout this article because Node treats JavaScript code as a commonJS module by default. You can also use ES6 modules if you want.

According to the Node documentation, the callback API of the built-in fs module is more performant than the promise-based API. Therefore, most examples in this article will use the callback API.

How to read JSON files in Node.js

The Node runtime environment has the built-in require function and the fs module that you can use for loading or reading JSON files. Because require is globally available, you don’t need to require it.

However, you will need to require the fs module before using it. I will discuss how to read JSON files using the built-in fs module and require function in the following subsections.

How to load a JSON file using the global require function

You can use the global require function to synchronously load JSON files in Node. After loading a file using require, it is cached. Therefore, loading the file again using require will load the cached version. In a server environment, the file will be loaded again in the next server restart.

It is therefore advisable to use require for loading static JSON files such as configuration files that do not change often. Do not use require if the JSON file you load keeps changing, because it will cache the loaded file and use the cached version if you require the same file again. Your latest changes will not be reflected.

Assuming you have a config.json file with the following content:

{
    "port": "3000",
    "ip": "127.00.12.3"
}

You can load the config.json file in a JavaScript file using the code below. require will always load the JSON data as a JavaScript object:

const config = require('./config.json');
console.log(config);

How to read a JSON file using the fs.readFile method

You can use the readFile method to read JSON files. It asynchronously reads the contents of the entire file in memory, therefore it is not the most optimal method for reading large JSON files.

The readFile method takes three arguments. The code snippet below shows its function signature:

fs.readFile(path, options, callback);

The first argument, path, is the file name or the file descriptor. The second is an optional object argument, and the third is a callback function. You can also pass a string as the second argument instead of an object. If you pass a string, then it has to be encoded.

The callback function takes two arguments. The first argument is the error object if an error occurs, and the second is the serialized JSON data.

The code snippet below will read the JSON data in the config.json file and log it on the terminal:

const fs = require('fs');

fs.readFile('./config.json', 'utf8', (error, data) => {
     if(error){
        console.log(error);
        return;
     }
     console.log(JSON.parse(data));

})

Make sure to deserialize the JSON string passed to the callback function before you start working with the resulting JavaScript object.

How to read a JSON file using fs.readFileSync method

readFileSync is another built-in method for reading files in Node similar to readFile. The difference between the two is that readFile reads the file asynchronously while readFileSync reads the file synchronously. Therefore, readFileSync blocks the event loop and execution of the remaining code until all the data has been read.

To grasp the difference between synchronous and asynchronous code, you can read the article “Understanding asynchronous JavaScript” here.

Below is the function signature of fs.readFileSync:

fs.readFileSync(path, options);

path is the path to the JSON file you want to read, and you can pass an object as the second argument. The second argument is optional.

In the code snippet below, we are reading JSON data from the config.json file using readFileSync:

const { readFileSync } = require('fs');
const data = readFileSync('./config.json');
console.log(JSON.parse(data));

How to write to JSON files in Node.js

Just like reading JSON files, the fs module provides built-in methods for writing to JSON files.

You can use the writeFile and writeFileSync methods of the fs module. The difference between the two is that writeFile is asynchronous while writeFileSync is synchronous. Before writing a JSON file, make sure to serialize the JavaScript object to a JSON string using the JSON.stringify method.

How to write to JSON files using the fs.writeFile method

JSON.stringify will format your JSON data in a single line if you do not pass the optional formatting argument to the JSON.stringify method specifying how to format your JSON data.

If the path you pass to the writeFile method is for an existing JSON file, the method will overwrite the data in the specified file. It will create a new file if the file does not exist:

const { writeFile } = require('fs');

const path = './config.json';
const config = { ip: '192.0.2.1', port: 3000 };

writeFile(path, JSON.stringify(config, null, 2), (error) => {
  if (error) {
    console.log('An error has occurred ', error);
    return;
  }
  console.log('Data written successfully to disk');
});

How to write to JSON files using the fs.writeFileSync method

Unlike writeFile, writeFileSync writes to a file synchronously. If you use writeFileSync, you will block the execution of the event loop and the rest of the code until the operation is successful or an error occurs. It will create a new file if the path you pass doesn’t exist, and overwrites it if it does.

In the code snippet below, we are writing to the config.json file. We are wrapping the code in try-catch so that we can catch any errors:

const { writeFileSync } = require('fs');

const path = './config.json';
const config = { ip: '192.0.2.1', port: 3000 };

try {
  writeFileSync(path, JSON.stringify(config, null, 2), 'utf8');
  console.log('Data successfully saved to disk');
} catch (error) {
  console.log('An error has occurred ', error);
}

How to append a JSON file

Node doesn’t have a built-in function for appending or updating fields of an existing JSON file out of the box. You can, however, read the JSON file using the readFile method of the fs module, update it, and overwrite the JSON file with the updated JSON.

Below is a code snippet illustrating how to go about it:

const { writeFile, readFile } = require('fs');
const path = './config.json';

readFile(path, (error, data) => {
  if (error) {
    console.log(error);
    return;
  }
  const parsedData = JSON.parse(data);
  parsedData.createdAt = new Date().toISOString();
  writeFile(path, JSON.stringify(parsedData, null, 2), (err) => {
    if (err) {
      console.log('Failed to write updated data to file');
      return;
    }
    console.log('Updated file successfully');
  });
});

How to read and write to JSON files using third-party npm packages

In this section, we shall look at the most popular third-party Node packages for reading and writing data in JSON format.

How to use the jsonfile npm package for reading and writing JSON files

jsonfile is a popular npm package for reading and writing JSON files in Node. You can install it using the command below:

npm i jsonfile

It is similar to the readFile and writeFile methods of the fs module, though jsonfile has some advantages over the built-in methods.

Some of the features of this package are as follows:

  • It serializes and deserializes JSON out of the box
  • It has a built-in utility for appending data to a JSON file
  • Supports promise chaining

You can see the jsonfile package in action in the code snippet below:

const jsonfile = require('jsonfile');
const path = './config.json';

jsonfile.readFile(path, (err, data) => {
  if (err) {
    console.log(err);
    return;
  }
  console.log(data);
});

You can also use promise chaining instead of passing a callback function like in the above example:

const jsonfile = require('jsonfile');
const path = './config.json';

jsonfile
  .readFile(path)
  .then((data) => {
    console.log(data);
  })
  .catch((err) => {
    console.log(err);
  });

How to use the fs-extra npm package for reading and writing JSON files

fs-extra is another popular Node package you can use to work with files. Though you can use this package for managing JSON files, it has methods whose functions extend beyond just reading and writing JSON files.

As its name suggests, fs-extra has all the functionalities provided by the fs module and more. According to the documentation, you can use the fs-extra package instead of the fs module.

You need to first install fs-extra from npm before using it:

npm install fs-extra

The code below shows how you can read JSON files using the readJson method of the fs-extra package. You can use a callback function, promise chaining, or async/await:

const fsExtra = require('fs-extra');
const path = './config.json';

// Using callback
fsExtra.readJson(path, (error, config) => {
  if (error) {
    console.log('An error has occurred');
    return;
  }
  console.log(config);
});

// Using promise chaining
fsExtra
  .readJson(path)
  .then((config) => {
    console.log(config);
  })
  .catch((error) => {
    console.log(error);
  });

// Using async/await
async function readJsonData() {
  try {
    const config = await fsExtra.readJson(path);
    console.log(config);
  } catch (error) {
    console.log(error);
  }
}
readJsonData();

The code below illustrates how you can write JSON data using the writeJson method:

const { writeJson } = require('fs-extra');

const path = './config.json';
const config = { ip: '192.0.2.1', port: 3000 };

// Using callback
writeJson(path, config, (error) => {
  if (error) {
    console.log('An error has occurred');
    return;
  }
  console.log('Data written to file successfully ');
});

// Using promise chaining
writeJson(path, config)
  .then(() => {
    console.log('Data written to file successfully ');
  })
  .catch((error) => {
    console.log(error);
  });

// Using async/await
async function writeJsonData() {
  try {
    await writeJson(path, config);
    console.log('Data written to file successfully ');
  } catch (error) {
    console.log(error);
  }
}
writeJsonData();

Just like the fs module, fs-extra has both asynchronous and synchronous methods. You don’t need to stringify your JavaScript object before writing to a JSON file.

Similarly, you don’t need to parse to a JavaScript object after reading a JSON file. The module does it for you out of the box.

How to use the bfj npm package for reading and writing JSON files

bfj is another npm package you can use for handling data in JSON format. According to the documentation, it was created for managing large JSON datasets.

bfj implements asynchronous functions and uses pre-allocated fixed-length arrays to try and alleviate issues associated with parsing and stringifying large JSON or JavaScript datasets – bfj documentation

You can read JSON data using the read method. The read method is asynchronous and it returns a promise.

Assuming you have a config.json file, you can use the following code to read it:

const bfj = require('bfj');
const path = './config.json';

bfj
  .read(path)
  .then((config) => {
    console.log(config);
  })
  .catch((error) => {
    console.log(error);
  });

Similarly, you can use the the write method to write data to a JSON file:

const bfj = require('bfj');
const path = './config.json';

const config = { ip: '192.0.2.1', port: 3000 };
bfj
  .write(path, config)
  .then(() => {
    console.log('Data has been successfully written to disk');
  })
  .catch((error) => {
    console.log(error);
  });

bfj has lots of functions that you can read about in the documentation. It was created purposely for handling large JSON data. It is also slow, so you should use it only if you are handling relatively large JSON datasets.

Conclusion

As explained in the above sections, JSON is one of the most popular formats for data exchange over the internet.

The Node runtime environment has the built-in fs module you can use to work with files in general. The fs module has methods that you can use to read and write to JSON files using the callback API, promise-based API, or synchronous API.

Because methods of the callback API are more performant than that of the promise-based API, as highlighted in the documentation, you are better off using the callback API.

In addition to the built-in fs module, several popular third-party packages such as jsonfile, fs-extra, and bfj exist. They have additional utility functions that make working with JSON files a breeze. On the flip side, you should evaluate the limitations of adding third-party packages to your application.

200’s only Monitor failed and slow network requests in production

Deploying a Node-based web app or website is the easy part. Making sure your Node instance continues to serve resources to your app is where things get tougher. If you’re interested in ensuring requests to the backend or third party services are successful, try LogRocket. https://logrocket.com/signup/

LogRocket is like a DVR for web and mobile apps, recording literally everything that happens while a user interacts with your app. Instead of guessing why problems happen, you can aggregate and report on problematic network requests to quickly understand the root cause.

LogRocket instruments your app to record baseline performance timings such as page load time, time to first byte, slow network requests, and also logs Redux, NgRx, and Vuex actions/state. .
Joseph Mawa A very passionate open source contributor and technical writer

One Reply to “Reading and writing JSON files in Node.js: A complete…”

Leave a Reply