jsonfile vs lowdb vs write-json-file
Choosing the Right Tool for JSON File Operations in Node.js
jsonfilelowdbwrite-json-fileSimilar Packages:

Choosing the Right Tool for JSON File Operations in Node.js

jsonfile, lowdb, and write-json-file address different layers of JSON file management in Node.js. jsonfile is a dedicated utility for reading and writing JSON files with built-in error handling and formatting options. lowdb is a lightweight local database that uses JSON files as storage, providing a simple API for querying and modifying data. write-json-file focuses specifically on the atomic writing of JSON data to files, ensuring data integrity during write operations. Each serves a distinct purpose: direct file I/O, in-memory database functionality, and safe file writing respectively.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
jsonfile01,21210.9 kB24 months agoMIT
lowdb022,57622.9 kB163 years agoMIT
write-json-file02257.38 kB0a year agoMIT

JSON File Operations: jsonfile vs lowdb vs write-json-file

When working with JSON data in Node.js applications, developers often face the choice between direct file manipulation, lightweight database solutions, and atomic write operations. The packages jsonfile, lowdb, and write-json-file each solve different problems in this space. Let's examine how they approach common challenges.

📝 Basic Reading and Writing

jsonfile provides straightforward methods for reading and writing JSON files with automatic parsing and stringification.

const jsonfile = require('jsonfile');

// Reading JSON
const obj = await jsonfile.readFile('./data.json');
console.log(obj.name);

// Writing JSON with formatting
await jsonfile.writeFile('./data.json', { name: 'John' }, { spaces: 2 });

lowdb reads and writes JSON through its database instance, treating the file as a persistent data store.

const { Low } = require('lowdb');
const { JSONFile } = require('lowdb/node');

const db = new Low(new JSONFile('data.json'));
await db.read();

// Access data
console.log(db.data.name);

// Write data
db.data.name = 'John';
await db.write();

write-json-file focuses exclusively on writing JSON data safely to files.

const writeJsonFile = require('write-json-file');

// Atomic write operation
await writeJsonFile('./data.json', { name: 'John' }, { indent: 2 });

// Note: No built-in reading capability - pair with fs.readFile or jsonfile

🔒 Data Integrity and Atomic Writes

jsonfile performs standard write operations that can potentially leave corrupted files if the process crashes mid-write.

// Standard write - vulnerable to interruption
await jsonfile.writeFile('./config.json', config);
// If process crashes here, file may be corrupted

lowdb inherits the same vulnerability as it uses standard file writing internally.

// Database write - also vulnerable to interruption
db.data.users.push(newUser);
await db.write();
// Crash during write could corrupt the entire database file

write-json-file implements atomic writes by writing to a temporary file first, then renaming it.

// Atomic write - safe from interruptions
await writeJsonFile('./config.json', config);
// Writes to temp file first, then renames - never leaves partial data

🔍 Data Querying and Manipulation

jsonfile requires manual data manipulation after reading - no built-in querying.

const data = await jsonfile.readFile('./users.json');
// Manual filtering
const activeUsers = data.users.filter(u => u.active);
const user = data.users.find(u => u.id === 123);

lowdb provides lodash-based chaining for querying and modifying data directly.

const activeUsers = db.get('users')
  .filter({ active: true })
  .value();

const user = db.get('users')
  .find({ id: 123 })
  .value();

// Direct modification
db.get('users').push({ id: 124, name: 'Jane' }).write();

write-json-file offers no querying capabilities - it's write-only.

// Must manage data structure externally
const data = { users: [...] }; // Managed in memory
await writeJsonFile('./users.json', data);

⚡ Performance Considerations

jsonfile loads entire files into memory for each operation, suitable for small to medium files.

// Entire file loaded into memory
const largeData = await jsonfile.readFile('./large-dataset.json');
// Memory usage scales with file size

lowdb keeps data in memory after initial load, providing fast access but requiring full file reloads on write.

// Initial load into memory
await db.read();

// Fast in-memory operations
const result = db.get('largeArray').find({ id: 999 }).value();

// Full file rewrite on any change
await db.write();

write-json-file optimizes only the write path with atomic operations, but still requires full data serialization.

// Efficient atomic write, but still serializes entire object
await writeJsonFile('./state.json', largeStateObject);

🛠️ Error Handling and Edge Cases

jsonfile handles common edge cases like missing directories and provides detailed error messages.

try {
  const data = await jsonfile.readFile('./missing.json');
} catch (err) {
  // Clear error handling
  console.error('File not found or invalid JSON:', err.message);
}

// Auto-creates directories
await jsonfile.writeFile('./nested/dir/file.json', data, { mkdirp: true });

lowdb provides basic error handling but requires manual setup for missing files.

try {
  await db.read();
} catch (err) {
  // Handle missing or corrupted database
  db.data = { users: [] }; // Reset to default
  await db.write();
}

write-json-file focuses on write-time errors and ensures cleanup of temporary files.

try {
  await writeJsonFile('./critical.json', importantData);
} catch (err) {
  // Write failed, but no partial data left behind
  console.error('Atomic write failed:', err.message);
}

🌐 Real-World Usage Patterns

Configuration Management

For application configuration files that need reliable updates:

// Using write-json-file for atomic config updates
const writeJsonFile = require('write-json-file');

async function updateConfig(newSettings) {
  const currentConfig = await jsonfile.readFile('./config.json');
  const updatedConfig = { ...currentConfig, ...newSettings };
  await writeJsonFile('./config.json', updatedConfig);
}

Local Development Database

For prototyping and development with simple querying needs:

// Using lowdb for local data store
const { Low } = require('lowdb');
const { JSONFile } = require('lowdb/node');

const db = new Low(new JSONFile('dev-data.json'));
await db.read();

// Easy querying during development
const activeUsers = db.get('users').filter({ status: 'active' }).value();

Simple Data Persistence

For straightforward JSON file operations without database overhead:

// Using jsonfile for simple save/load operations
const jsonfile = require('jsonfile');

async function saveUserPreferences(userId, prefs) {
  const file = `./users/${userId}-prefs.json`;
  await jsonfile.writeFile(file, prefs, { spaces: 2 });
}

async function loadUserPreferences(userId) {
  const file = `./users/${userId}-prefs.json`;
  return await jsonfile.readFile(file);
}

📊 Feature Comparison

Featurejsonfilelowdbwrite-json-file
Read Support✅ Full✅ Full❌ None
Write Support✅ Standard✅ Standard✅ Atomic
Querying❌ Manual✅ Lodash chaining❌ None
Data Integrity⚠️ Standard writes⚠️ Standard writes✅ Atomic operations
Memory UsagePer-operation loadPersistent in-memoryPer-operation load
Best ForGeneral JSON I/OLocal databaseCritical writes

💡 The Bottom Line

jsonfile is your go-to for general JSON file operations - think configuration files, simple data persistence, or any scenario where you need reliable read/write capabilities without database complexity. It's the Swiss Army knife of JSON file handling.

lowdb shines when you need a lightweight, file-based database with querying capabilities. Perfect for development tools, CLI applications, or prototypes where you want database-like operations without the setup overhead. Just remember its limitations with concurrent access and large datasets.

write-json-file is specialized for scenarios where data integrity during writes is non-negotiable. Use it for critical configuration updates, state persistence in production environments, or any situation where file corruption during writes could cause serious problems.

Pro Tip: These packages aren't mutually exclusive. Many production applications use jsonfile for general operations, write-json-file for critical writes, and avoid lowdb in favor of proper databases for anything beyond development or simple tools.

Choose based on your specific needs: general I/O (jsonfile), querying capabilities (lowdb), or write safety (write-json-file). Understanding these distinctions helps you build more reliable and maintainable Node.js applications.

How to Choose: jsonfile vs lowdb vs write-json-file

  • jsonfile:

    Choose jsonfile when you need straightforward, reliable reading and writing of JSON files with minimal setup. It's ideal for configuration files, simple data persistence, or any scenario where you need to serialize/deserialize JSON to/from disk without database overhead. The package handles common edge cases like directory creation and provides both synchronous and asynchronous APIs.

  • lowdb:

    Choose lowdb when you need a simple, file-based database for small to medium datasets with query capabilities. It's perfect for prototyping, local development, CLI tools, or applications that need to store structured data with basic filtering and chaining operations. Avoid it for high-concurrency scenarios or large datasets where performance becomes critical.

  • write-json-file:

    Choose write-json-file when data integrity during write operations is paramount, such as in production environments where partial writes could corrupt critical data. It's specifically designed for atomic writes using temporary files and renaming, making it suitable for configuration management, state persistence, or any scenario where file corruption during writes must be prevented.

README for jsonfile

Node.js - jsonfile

Easily read/write JSON files in Node.js. Note: this module cannot be used in the browser.

npm Package linux build status windows Build status

Standard JavaScript

Why?

Writing JSON.stringify() and then fs.writeFile() and JSON.parse() with fs.readFile() enclosed in try/catch blocks became annoying.

Installation

npm install --save jsonfile

API


readFile(filename, [options], callback)

options (object, default undefined): Pass in any fs.readFile options or set reviver for a JSON reviver.

  • throws (boolean, default: true). If JSON.parse throws an error, pass this error to the callback. If false, returns null for the object.
const jsonfile = require('jsonfile')
const file = '/tmp/data.json'
jsonfile.readFile(file, function (err, obj) {
  if (err) console.error(err)
  console.dir(obj)
})

You can also use this method with promises. The readFile method will return a promise if you do not pass a callback function.

const jsonfile = require('jsonfile')
const file = '/tmp/data.json'
jsonfile.readFile(file)
  .then(obj => console.dir(obj))
  .catch(error => console.error(error))

readFileSync(filename, [options])

options (object, default undefined): Pass in any fs.readFileSync options or set reviver for a JSON reviver.

  • throws (boolean, default: true). If an error is encountered reading or parsing the file, throw the error. If false, returns null for the object.
const jsonfile = require('jsonfile')
const file = '/tmp/data.json'

console.dir(jsonfile.readFileSync(file))

writeFile(filename, obj, [options], callback)

options: Pass in any fs.writeFile options or set replacer for a JSON replacer. Can also pass in spaces, or override EOL string or set finalEOL flag as false to not save the file with EOL at the end.

const jsonfile = require('jsonfile')

const file = '/tmp/data.json'
const obj = { name: 'JP' }

jsonfile.writeFile(file, obj, function (err) {
  if (err) console.error(err)
})

Or use with promises as follows:

const jsonfile = require('jsonfile')

const file = '/tmp/data.json'
const obj = { name: 'JP' }

jsonfile.writeFile(file, obj)
  .then(res => {
    console.log('Write complete')
  })
  .catch(error => console.error(error))

formatting with spaces:

const jsonfile = require('jsonfile')

const file = '/tmp/data.json'
const obj = { name: 'JP' }

jsonfile.writeFile(file, obj, { spaces: 2 }, function (err) {
  if (err) console.error(err)
})

overriding EOL:

const jsonfile = require('jsonfile')

const file = '/tmp/data.json'
const obj = { name: 'JP' }

jsonfile.writeFile(file, obj, { spaces: 2, EOL: '\r\n' }, function (err) {
  if (err) console.error(err)
})

disabling the EOL at the end of file:

const jsonfile = require('jsonfile')

const file = '/tmp/data.json'
const obj = { name: 'JP' }

jsonfile.writeFile(file, obj, { spaces: 2, finalEOL: false }, function (err) {
  if (err) console.log(err)
})

appending to an existing JSON file:

You can use fs.writeFile option { flag: 'a' } to achieve this.

const jsonfile = require('jsonfile')

const file = '/tmp/mayAlreadyExistedData.json'
const obj = { name: 'JP' }

jsonfile.writeFile(file, obj, { flag: 'a' }, function (err) {
  if (err) console.error(err)
})

writeFileSync(filename, obj, [options])

options: Pass in any fs.writeFileSync options or set replacer for a JSON replacer. Can also pass in spaces, or override EOL string or set finalEOL flag as false to not save the file with EOL at the end.

const jsonfile = require('jsonfile')

const file = '/tmp/data.json'
const obj = { name: 'JP' }

jsonfile.writeFileSync(file, obj)

formatting with spaces:

const jsonfile = require('jsonfile')

const file = '/tmp/data.json'
const obj = { name: 'JP' }

jsonfile.writeFileSync(file, obj, { spaces: 2 })

overriding EOL:

const jsonfile = require('jsonfile')

const file = '/tmp/data.json'
const obj = { name: 'JP' }

jsonfile.writeFileSync(file, obj, { spaces: 2, EOL: '\r\n' })

disabling the EOL at the end of file:

const jsonfile = require('jsonfile')

const file = '/tmp/data.json'
const obj = { name: 'JP' }

jsonfile.writeFileSync(file, obj, { spaces: 2, finalEOL: false })

appending to an existing JSON file:

You can use fs.writeFileSync option { flag: 'a' } to achieve this.

const jsonfile = require('jsonfile')

const file = '/tmp/mayAlreadyExistedData.json'
const obj = { name: 'JP' }

jsonfile.writeFileSync(file, obj, { flag: 'a' })

License

(MIT License)

Copyright 2012-2016, JP Richardson jprichardson@gmail.com