npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

json-file-crud

v1.3.0

Published

A simple, robust, and thread-safe CRUD library for managing JSON objects in files with unique fields, auto-ID, and advanced features

Readme

JsonFileCRUD

A simple, robust, and thread-safe CRUD library for managing JSON objects in files using Node.js.

Features

  • Simple API - Easy to use CRUD operations
  • Promise/Async Support - Full async/await API alongside callback methods ✨ New in v1.3
  • Thread-safe - Sequential operations with automatic queuing
  • Auto-ID assignment - Automatic ID generation for new items (configurable)
  • Unique Fields - Prevent duplicate values in specified fields ✨ New in v1.1
  • Concurrent Operations - Thread-safe operations with automatic queuing
  • Custom ID Fields - Use any field name as the primary key (default: 'id')
  • Directory Creation - Automatically creates directories if they don't exist ✨ New in v1.1
  • Convenience Functions - Helper functions for quick setup ✨ New in v1.1
  • TypeScript Support - Full TypeScript definitions for IDE support ✨ New in v1.2
  • Error Handling - Comprehensive error handling and detailed error messages
  • Zero dependencies - Built with only Node.js built-in modules
  • ESM support - Full ES modules support

Installation

npm install json-file-crud

Quick Start

import JsonFileCRUD, { createCrud } from 'json-file-crud';

// Standard usage
const db = new JsonFileCRUD('./data.json');

// Quick setup with convenience function
const db2 = createCrud('./users.json');

// Advanced configuration with unique fields
const userDb = new JsonFileCRUD('./users.json', {
  uniqueFields: ['email', 'username'],
  autoId: true
});

// Create a new item
db.create({ name: 'John', age: 30 }, (err, result) => {
  if (err) {
    console.error('Error:', err.message);
    return;
  }
  console.log('Created:', result); // { name: 'John', age: 30, id: 1 }
});

// Read all items
db.readAll((err, items) => {
  if (err) throw err;
  console.log('All items:', items);
});

// Find by ID
db.findById(1, (err, item) => {
  if (err) throw err;
  console.log('Found:', item);
});

// Update an item
db.update(1, { age: 31 }, (err, updatedItem) => {
  if (err) throw err;
  console.log('Updated:', updatedItem);
});

// Delete an item
db.delete(1, (err, deletedItem) => {
  if (err) throw err;
  console.log('Deleted:', deletedItem);
});

Async/Await Usage

// Same operations using async/await
try {
  const user = await db.createAsync({ name: 'John', age: 30 });
  console.log('Created:', user);
  
  const foundUser = await db.findByIdAsync(user.id);
  console.log('Found:', foundUser);
  
  const updatedUser = await db.updateAsync(user.id, { age: 31 });
  console.log('Updated:', updatedUser);
  
  const deletedUser = await db.deleteAsync(user.id);
  console.log('Deleted:', deletedUser);
} catch (error) {
  console.error('Error:', error.message);
}

API Reference

Constructor

new JsonFileCRUD(filePath, options)

Creates a new JsonFileCRUD instance.

  • filePath (string): Path to the JSON file (directories will be created if they don't exist)
  • options (object, optional):
    • idField (string): Name of the ID field (default: 'id')
    • uniqueFields (array): Array of field names that must be unique (default: [])
    • autoId (boolean): Enable automatic ID assignment (default: true)
// Default settings
const db = new JsonFileCRUD('./data.json');

// Custom ID field
const products = new JsonFileCRUD('./products.json', { idField: 'productId' });

// Unique fields validation
const users = new JsonFileCRUD('./users.json', { 
  uniqueFields: ['email', 'username'] 
});

// Disable auto-ID
const manualDb = new JsonFileCRUD('./manual.json', { autoId: false });

// Deep directory path (automatically created)
const deepDb = new JsonFileCRUD('./data/nested/deep/file.json');

Convenience Functions

createCrud(filePath, options)

Quick way to create a JsonFileCRUD instance.

import { createCrud } from 'json-file-crud';

const db = createCrud('./data.json', { uniqueFields: ['email'] });

CRUD Operations

create(item, callback)

Creates a new item. Auto-assigns an ID if not provided.

  • item (object): The item to create
  • callback (function): (error, createdItem) => {}
db.create({ name: 'Alice', email: '[email protected]' }, (err, result) => {
  // result: { name: 'Alice', email: '[email protected]', id: 1 }
});

readAll(callback)

Reads all items from the file.

  • callback (function): (error, items) => {}
db.readAll((err, items) => {
  // items: array of all items
});

findById(id, callback)

Finds an item by its ID.

  • id (any): The ID to search for
  • callback (function): (error, item) => {}
db.findById(1, (err, item) => {
  // item: the found item or null if not found
});

findBy(filterFunction, callback)

Finds items that match a filter function.

  • filterFunction (function): Function that returns true for matching items
  • callback (function): (error, items) => {}
// Find all adults
db.findBy(item => item.age >= 18, (err, adults) => {
  // adults: array of matching items
});

// Find by name
db.findBy(item => item.name === 'John', (err, johns) => {
  // johns: array of items named John
});

update(id, data, callback)

Updates an existing item.

  • id (any): The ID of the item to update
  • data (object): The data to update (merged with existing item)
  • callback (function): (error, updatedItem) => {}
db.update(1, { age: 25, city: 'New York' }, (err, updated) => {
  // updated: the item with merged data
});

delete(id, callback)

Deletes an item by ID.

  • id (any): The ID of the item to delete
  • callback (function): (error, deletedItem) => {}
db.delete(1, (err, deleted) => {
  // deleted: the item that was removed
});

deleteAll(callback)

Deletes all items from the database.

  • callback (function): (error) => {}
db.deleteAll((err) => {
  if (err) throw err;
  console.log('All items deleted');
});

count(callback)

Returns the total number of items.

  • callback (function): (error, count) => {}
db.count((err, total) => {
  console.log('Total items:', total);
});

writeAll(items, callback)

Replaces all data in the file with a new array of items.

  • items (array): Array of items to write
  • callback (function): (error) => {}
const newData = [
  { name: 'Item 1', id: 1 },
  { name: 'Item 2', id: 2 }
];

db.writeAll(newData, (err) => {
  if (!err) console.log('Data replaced successfully');
});

Promise-based API

All methods have async counterparts that return Promises. Simply add Async to the method name:

Async Method Names

All callback methods have async counterparts. Add Async to the method name:

// Using async/await
try {
  const user = await db.createAsync({ name: 'John', age: 30 });
  const allUsers = await db.readAllAsync();
  const foundUser = await db.findByIdAsync(user.id);
  const updatedUser = await db.updateAsync(user.id, { age: 31 });
  await db.deleteAsync(user.id);
} catch (error) {
  console.error('Operation failed:', error.message);
}

// Using Promises
db.createAsync({ name: 'Jane', age: 25 })
  .then(user => db.findByIdAsync(user.id))
  .then(foundUser => console.log('Found:', foundUser))
  .catch(error => console.error('Error:', error.message));

Advanced Features

Unique Fields

Prevent duplicate values in specified fields:

const userDb = new JsonFileCRUD('./users.json', {
  uniqueFields: ['email', 'username']
});

// This will fail if email already exists
userDb.create({ 
  name: 'John', 
  email: '[email protected]' 
}, (err, user) => {
  // err.message: "Item with email '[email protected]' already exists"
});

Auto-ID Control

Disable automatic ID assignment:

const db = new JsonFileCRUD('./data.json', { autoId: false });

// No ID will be auto-generated
db.create({ name: 'Test' }, (err, item) => {
  // item: { name: 'Test' } (no id field)
});

Directory Creation

Automatically creates directories for deep paths:

// This will create ./data/users/ directories if they don't exist
const db = new JsonFileCRUD('./data/users/profiles.json');

Examples

For comprehensive examples, see the examples directory:

Quick Examples

// Basic usage with unique fields
import JsonFileCRUD, { createCrud } from 'json-file-crud';

const userDb = createCrud('./users.json', {
  uniqueFields: ['email', 'username']
});

// Delete all users
userDb.deleteAll((err) => {
  console.log('All users deleted');
});

// Example with auto-ID disabled
const manualDb = new JsonFileCRUD('./manual.json', { autoId: false });
manualDb.create({ name: 'Test' }, (err, item) => {
  // item: { name: 'Test' } (no auto-generated ID)
});

To run examples:

npm run examples
# or individually:
node examples/basic-usage.js

TypeScript Support

Type definitions are provided via lib/json-file-crud.d.ts so the library can be used comfortably in TypeScript projects with autocompletion and compile-time checks.

File Format

JsonFileCRUD stores data as a JSON array in the specified file:

[
  { "id": 1, "name": "John", "age": 30 },
  { "id": 2, "name": "Jane", "age": 25 }
]

If the file doesn't exist, it will be created automatically on the first write operation.

Performance Considerations

  • Small to medium datasets: JsonFileCRUD is ideal for applications with up to ~10,000 items
  • File I/O: Every operation reads/writes the entire file, so performance scales with file size
  • Memory usage: The entire dataset is loaded into memory during operations
  • Concurrent access: Operations are queued, so high-concurrency scenarios may experience delays

For larger datasets or high-performance requirements, consider using a dedicated database.

Contributing

Contributions are welcome! Here are some ways you can help improve JsonFileCRUD:

Ideas for Contributions

  • Batch Operations: Add bulk insert/update/delete operations
  • File Locking: Add file locking for multi-process safety
  • Enhanced Documentation: Improve documentation and add more examples

How to Contribute

  1. Fork the Repository: Create your own fork of the project
  2. Create a Feature Branch: git checkout -b feature/your-feature-name
  3. Write Tests: Ensure your changes are well-tested
  4. Follow Code Style: Keep the code clean and consistent
  5. Update Documentation: Add or update relevant documentation
  6. Submit a Pull Request: Describe your changes clearly

License

MIT License - see LICENSE file for details.