Node.js can read and write JSON files using its built-in fs module, with no extra packages needed. You use fs.readFile or fs.readFileSync to load JSON, and fs.writeFile or fs.writeFileSync to save it, always converting between JSON text and JavaScript objects with JSON.parse() and JSON.stringify(). This guide explains the synchronous and asynchronous approaches, common pitfalls like encoding and pretty-printing, and how to handle large files or concurrent writes.
Why JSON Is Everywhere in Node.js
JSON (JavaScript Object Notation) is the standard data format for configuration files, API responses, and data storage in Node.js. Because JSON syntax is a subset of JavaScript object literal syntax, Node.js can parse and generate it natively. The fs (file system) module provides all the file operations you need, and the global JSON object handles conversion. This combination makes reading and writing JSON files one of the most common tasks in Node development.
Reading JSON Files: Synchronous vs. Asynchronous
Node.js offers two styles for file reading. The synchronous methods block the event loop until the operation completes, which is fine for startup scripts or small files. The asynchronous methods take a callback or return a Promise, letting other code run while the file loads.
Synchronous example:
const fs = require('fs');
const data = JSON.parse(fs.readFileSync('config.json', 'utf8'));
console.log(data.port);
Asynchronous with callbacks:
fs.readFile('config.json', 'utf8', (err, data) => {
if (err) throw err;
const config = JSON.parse(data);
console.log(config.port);
});
Asynchronous with Promises (fs.promises):
const fs = require('fs').promises;
async function loadConfig() {
const data = await fs.readFile('config.json', 'utf8');
return JSON.parse(data);
}
For most applications, the Promise-based approach is cleaner because it avoids callback nesting and works well with async/await. Always use the utf8 encoding parameter; without it, readFile returns a Buffer, and JSON.parse would fail unless you call .toString().
Writing JSON Files: Pretty-Printing and Overwrites
To write JSON, you convert a JavaScript object to a string with JSON.stringify() and then write that string to a file. By default, JSON.stringify produces compact output with no spaces, which is fine for machines but hard to read. Pass null and 2 as the second and third arguments to indent with two spaces:
const fs = require('fs');
const config = { port: 3000, debug: true };
fs.writeFileSync('config.json', JSON.stringify(config, null, 2));
The asynchronous version uses fs.writeFile (or fs.promises.writeFile). Both overwrite the file if it exists. To append to an existing JSON file, you must read it first, modify the object, and then write the whole thing back—there is no built-in “append to JSON” operation because JSON requires a single valid document.
Handling Errors and Invalid JSON
If the file does not exist or contains malformed JSON, your program will crash unless you handle it. Always wrap JSON.parse in a try/catch block, especially when reading user-generated files:
try {
const data = JSON.parse(fs.readFileSync('data.json', 'utf8'));
} catch (err) {
console.error('Invalid JSON or file missing:', err.message);
}
For asynchronous methods, check the error parameter in callbacks or use try/catch in async functions. A common mistake is assuming the file exists; use fs.existsSync or check the error code ENOENT to handle missing files gracefully.
Choosing Between readFileSync and readFile
Use readFileSync when:
- You are reading a small config file at startup.
- You are writing a simple script or CLI tool.
- You are in a module that is loaded once.
Use readFile (async) when:
- You are building a web server or API that handles many requests.
- The file is large (over a few MB).
- You want to avoid blocking the event loop.
Blocking the event loop in a server makes all requests wait, so async is strongly preferred in production servers. For one-off scripts, sync is simpler and easier to read.
Common Problems and How to Avoid Them
Here are frequent pitfalls when working with JSON files in Node.js:
- Forgetting the encoding: Without
'utf8', you get a Buffer. Always specify it. - Writing without pretty-printing: The file becomes one long line, making debugging hard. Use
JSON.stringify(data, null, 2). - Not handling missing files: Use try/catch or check existence first.
- Concurrent writes: If two processes write to the same file simultaneously, one may overwrite the other. Use a queue or atomic writes (write to a temp file, then rename).
- Using
require()for JSON: Node.js canrequire('file.json')directly, but it caches the result. If the file changes, you won’t see updates. Usefs.readFilefor dynamic data.
Alternatives for Large Files or Frequent Writes
If you are storing large datasets or need frequent updates, reading and writing the entire file each time becomes inefficient. Consider using a database like SQLite or a dedicated JSON store like lowdb (which still uses files but with better caching). For streaming large JSON, you can use JSONStream or the built-in stream module, but that adds complexity. For most configuration and small data needs, the native fs approach is perfectly adequate.
Frequently Asked Questions
Can I use require() to read a JSON file?
Yes, require('./file.json') works and returns a parsed object. However, Node.js caches the result, so if the file changes during runtime, you won’t see the new data unless you delete the cache entry. For static config, it’s fine; for dynamic data, use fs.
How do I pretty-print JSON with tabs instead of spaces?
Pass '\t' as the third argument to JSON.stringify: JSON.stringify(data, null, '\t'). The second argument (replacer) can be null to keep all properties.
What is the difference between writeFile and createWriteStream for JSON?
writeFile writes the whole string at once, which is fine for files up to a few hundred MB. createWriteStream lets you write data in chunks, which is useful for very large JSON arrays that you build incrementally, but you must manage the stream lifecycle and handle backpressure.
How do I append data to a JSON array in a file?
Read the file, parse it, push the new item to the array, then write the whole array back. There is no built-in append for JSON because the file must remain a valid JSON document. For high-frequency appends, consider a different storage format.
Why does my JSON file have no newlines at the end?
By default, writeFile writes exactly the string you give it. If you want a trailing newline, add '\n' to the end: JSON.stringify(data, null, 2) + '\n'. Many tools expect a final newline, so it’s a good habit.
Related
Formula used
in t | File size (bytes) | bytes | 1024 | 1 | 1000000000 in d | Transfer speed (Mbps) | Mbps | 100 | 0.1 | 10000 out time | Transfer time (seconds) | s | (t * 8) / (d * 1000000) | 2 out minutes | Transfer time (minutes) | min | time / 60 | 2
Each line is one input (in, sel, list) or one result (out: label, unit, formula, decimals). How the calculators work
Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.
More cards in this drawer
- Delete Picture Kik? How to Remove Photos
- Are Networked Implants Safe? What If One Fails?
- How to Stop WordPress Comment Spam: A Layered Guide
- What Happens to X Replies, DMs, and Followers After Deletion?
- Data Breaches That Shook the World
- Disable Google Assistant: Turn It Off on Android & Home