I Got Tired of Writing the Same JSON File Boilerplate in Node.js...
...so I made a much saner way to work with JSON files

Every time you needed to read or update a JSON file in NodeJS, you ended up writing the exact same boilerplate.
You know the drill:
- Read the file.
- Parse the JSON.
- Wrap everything in
try/catchbecause the file might not exist. - Create a fallback object.
- Stringify the result.
- Write it back to disk.
- Don't forget to handle the errors...
Do this in a few different places, and your codebase quickly turns into a mess of repetitive file-system wrappers.
I looked at existing alternatives. Popular packages like jsonfile and fs-extra handle parsing and stringifying perfectly well. But they do not help much when you need to:
- merge new keys into an existing configuration;
- create a missing file using a default structure;
- safely handle values that JSON cannot serialize;
- prevent overlapping writes to the same file.
- not handle errors yourself
You still have to build custom logic around them.
So I stopped copying the same utility functions between projects and published Boma β a zero-dependency helper for working with JSON-based state and configuration files.
Reading Files with Automatic Fallbacks
When a file does not exist, Boma does not crash. It creates the file using the default structure you provide and returns that structure.
import { readJSON } from 'boma';
// If config.json does not exist, Boma creates it
// with { port: 8080 } and returns that object.
const config = readJSON({
filePath: './config.json',
createIfNotFound: {
port: 8080
}
});
No try/catch required.
Updating Data Without the ReadβParseβWrite Dance
Normally, adding a value to a JSON file means reading the file, parsing it, modifying the resulting object, stringifying it, and writing it back.
Boma provides addToJSON to handle the entire operation in one call.
For objects, it performs a shallow merge. For arrays, it concatenates the values.
import { addToJSON } from 'boma';
addToJSON({
filePath: './logs.json',
dataToAdd: {
lastRun: Date.now()
},
format: true
});
Operations are queued internally per file. If several updates are triggered from the same Node.js process, they will not overlap and corrupt the file.
Handling Non-Serializable Values
Native JSON.stringify silently drops values such as undefined and functions. It also converts values like NaN and Infinity to null.
Boma can detect these serialization issues or replace unsupported values with readable string markers.
import { saveJSON } from 'boma';
saveJSON({
filePath: './debug.json',
objToSave: {
status: undefined,
brokenMath: NaN,
handler: () => {}
},
replaceNonSerializable: true,
format: true
});
The resulting file:
{
"status": "undefined",
"brokenMath": "non-finite-number",
"handler": "function"
}
Synchronous by Default, Asynchronous When Needed
By default, Boma runs synchronously.
To use Promise-based operations, add async: true to the options object of any method.
const config = await readJSON({
filePath: './config.json',
createIfNotFound: {
port: 8080
},
async: true
});
The imports and overall API remain the same.
Installation
npm install boma
Fuck yeah, this thing is awesome.
Check it out on GitHub or install it from NPM:
npm i boma
Top comments (0)