Node.js Guide
Read & Write JSON Files in Node.js
Reading and writing JSON is the most common file operation in Node. Here's every method — sync, async, ESM, and error handling.
Quick answer: const data = JSON.parse(fs.readFileSync('data.json', 'utf8')) reads a JSON file. fs.writeFileSync('data.json', JSON.stringify(data, null, 2)) writes it back with 2-space formatting.
Read a JSON File (Sync)
const fs = require('fs');
const raw = fs.readFileSync('./data.json', 'utf8');
const data = JSON.parse(raw);
console.log(data.name); // "Sarah"
Pros: Simple, no async. Cons: Blocks the event loop — bad for large files or servers.
Read a JSON File (Async — Recommended)
const fs = require('fs/promises');
async function loadData() {
const raw = await fs.readFile('./data.json', 'utf8');
return JSON.parse(raw);
}
const data = await loadData();
console.log(data.name);
Async reads don't block your server. Use this in production.
Read JSON with ES Modules
import { readFile } from 'fs/promises';
const raw = await readFile('./data.json', 'utf8');
const data = JSON.parse(raw);
Or use the shorter JSON import with an import assertion (Node 20+):
import data from './data.json' with { type: 'json' };
Note: JSON imports are cached. If the file changes, use fs.readFile instead.
Write a JSON File
const fs = require('fs');
const data = {
name: 'Sarah',
age: 25,
tags: ['dev', 'writer']
};
fs.writeFileSync('./output.json', JSON.stringify(data, null, 2));
The null, 2 arguments in JSON.stringify produce pretty-printed JSON with 2-space indentation.
💡 Async version: Replace writeFileSync with await fs.writeFile from fs/promises.
Update an Existing JSON File
const fs = require('fs');
function updateJSON(filePath, updates) {
const raw = fs.readFileSync(filePath, 'utf8');
const data = JSON.parse(raw);
const merged = { ...data, ...updates };
fs.writeFileSync(filePath, JSON.stringify(merged, null, 2));
return merged;
}
updateJSON('./data.json', { age: 26, updated: true });
Handle Errors Safely
const fs = require('fs/promises');
async function loadSafe(path) {
try {
const raw = await fs.readFile(path, 'utf8');
return JSON.parse(raw);
} catch (err) {
if (err.code === 'ENOENT') {
console.error('File not found:', path);
} else if (err instanceof SyntaxError) {
console.error('Invalid JSON in:', path);
} else {
console.error('Unknown error:', err);
}
return null;
}
}
Always check both file errors (ENOENT) and JSON errors (SyntaxError). A missing file and malformed JSON are different bugs.
📊 When to Use Which Method
- fs.readFileSync — Small files, scripts, config loading at startup
- fs/promises.readFile — Production code, servers, anything user-facing
- require('./data.json') — Static config files that don't change
- import data from './data.json' — Modern ESM equivalent
- Streaming — Files over ~50MB (use readline or stream-json)
❓ Frequently Asked Questions
How do I read a JSON file in Node.js?
;Use fs.readFileSync('./data.json', 'utf8') then JSON.parse(). For async, use fs/promises with await.
require vs fs.readFileSync for JSON?
require caches — reads once. fs.readFileSync always reads from disk. Use require for static config, fs for changing data.
How do I write pretty-printed JSON?
JSON.stringify(obj, null, 2) — the third argument is the indent size.
How do I handle errors?
Wrap in try/catch. ENOENT is file not found. SyntaxError is invalid JSON. Handle both separately.