Parsing JSON with Node.js
By Flavio Copes
Learn how to parse JSON in Node.js with JSON.parse, read a JSON file with fs/promises, and when require() of JSON still makes sense in CommonJS.
If you have JSON data as part of a string, the best way to parse it is by using the JSON.parse method that’s part of the JavaScript standard since ECMAScript 5, and it’s provided by V8, the JavaScript engine that powers Node.js.
Example:
const data = '{ "name": "Flavio", "age": 35 }'
try {
const user = JSON.parse(data)
} catch(err) {
console.error(err)
}
Note that JSON.parse is synchronous, so the more the JSON file is big, the more time your program execution will be blocked until the JSON is finished parsing.
If JSON.parse throws and you can’t spot why, paste the string into my JSON formatter and validator — it points at the exact line and column of the error.
You can process the JSON asynchronously by wrapping it in a promise and a setTimeout call, which makes sure parsing takes place in the next iteration of the event loop:
const parseJsonAsync = (jsonString) => {
return new Promise(resolve => {
setTimeout(() => {
resolve(JSON.parse(jsonString))
})
})
}
const data = '{ "name": "Flavio", "age": 35 }'
parseJsonAsync(data).then(jsonData => console.log(jsonData))
If your JSON is in a file instead, you first have to read it, then call JSON.parse on the string.
Read a JSON file with fs/promises
Read the file as text, then parse it. This is the best option:
import fs from 'node:fs/promises'
try {
const fileContents = await fs.readFile('./file.json', 'utf8')
const data = JSON.parse(fileContents)
} catch (err) {
console.error(err)
}
Works the same in CommonJS with require('node:fs/promises') inside an async function. You get a fresh read every time, so updates to the file show up on the next call.
There’s also a sync option if you’re in a small script:
import fs from 'node:fs'
try {
const fileContents = fs.readFileSync('./file.json', 'utf8')
const data = JSON.parse(fileContents)
} catch (err) {
console.error(err)
}
require() of JSON (CommonJS only)
In CommonJS you can still do this:
const data = require('./file.json')
Since you used the .json extension, require() parses the JSON into an object for you.
Two caveats. First, require() only exists in CommonJS. In ESM you either read and parse the file like above, or import it directly:
import data from './file.json' with { type: 'json' }
The with { type: 'json' } part is mandatory.
Second, the result is cached. Call require() again after updating the file and you still get the old object until the process exits. The ESM import is cached in the same way.
That caching was designed for app configuration you load once at startup, and it’s a perfectly valid use case. It’s a problem only if the file can change while the app runs.
Callback-style fs.readFile
You can also read the file asynchronously with a callback:
import fs from 'node:fs'
fs.readFile('./file.json', 'utf8', (err, fileContents) => {
if (err) {
console.error(err)
return
}
try {
const data = JSON.parse(fileContents)
} catch(err) {
console.error(err)
}
})
Same idea as the promises version, just with a callback instead of await. Both work. The promises version is easier to read.
Want me to talk about your product? You can sponsor this site.
Related posts about node: