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 🙏

© 2025 – Pkg Stats / Ryan Hefner

leaf-db

v13.0.0

Published

Small file-based database for node.js

Downloads

391

Readme

Features

  • Strong-typed documents and queries.
  • Easy to embed as it does not require an HTTP server to run.
  • Can be used in the browser if persistent storage isn't required.
  • Uses JSON documents.
  • Tiny and 0 dependencies.

Table of Contents

Getting Started

leaf-db is meant as a simple database that allows for basic querying over JSON data without needing to set up a database server / connection like with MongoDB or SQLite.

Node does support working with SQLite directly, if you prefer a more stable, feature-complete database.

leaf-db can be used in the browser if persistent read / write isn't required.

Installation

npm i leaf-db

Example

Create a database using file storage with strong-typed documents:

import LeafDB from 'leaf-db';

type Document = {
  title: string
  name: string
}

const db = new LeafDB<Document>();

await db.open({ name: 'db', dir: process.cwd() });

const drafts = [
  { title: 'Lady', name: 'Mipha' },
  { title: 'Young Rito Warrior', name: 'Tulin' }
]
await Promise.all(drafts.map(async draft => db.insert(draft)));

// [{ _id: <string>, title: 'Young Rito Warrior', name: 'Tulin' }]
const characters = db.query({ name: 'Tulin' });

const tulin = characters[0];
tulin.title = 'Rito Warrior';

await db.update(tulin); // Overwrite existing document

await db.close();

Concepts

Document

Leaf-db stores data as JSON documents and saves them inside a JSONL file.

Keys

Document keys must be of type string and cannot start with $.

Every document is required to have an _id field. Leaf-db automatically creates an _id if the field does not exist on insertion. _id is required to be unique when inserting documents.

Values

Leaf-db only supports JSON values, which is defined as:

type Json =
  string |
  number |
  boolean |
  null |
  Json[] |
  { [key: string]: Json };

Persistence

Leaf-db stores the database in memory by default. To make use of persistence, simply open the database.

import LeafDB from 'leaf-db';

/** Create a new database, `db.jsonl`, in process.cwd() */
const db = new LeafDB();
await db.open({ name: 'db', dir: process.cwd() });

Corruption

When opening a database from storage, leaf-db will return documents that are corrupt. These documents are deleted once opened and cannot be recovered afterwards.

import LeafDB from 'leaf-db';

const db = new LeafDB({ name: 'db', dir: process.cwd() });
const corrupt = await db.open(); // Corrupt[]
type Corrupt = {
  raw: string;
  error: Error;
};

Queries

Leaf-db supports both literal values and operators. Example:

/**
 * Literal query where value must equal the query value
 * { name: 'tulin' } // No match
 * { name: 'Mipha' } // No match
 */
const a = { name: 'Tulin' };

/**
 * Objects and arrays match on partial matches
 * { eras: [] } // Match
 * { eras: ['era of the wilds'] } // No match
 * { eras: [Sky Era'] } // No Match
 */
const b = { eras: ['Era of the Wilds'] }

Operators

Operators allow for more complex queries. Operators must always be used in combination with values.

Number
$gt

Is greater than

const query = { a: { $gt: 3 } };

const a = { a: 2 }; // false
const b = { a: 3 }; // false
const c = { a: 4 }; // true
$gte

Is greater than or equal to

const query = { a: { $gte: 3 } };

const a = { a: 2 }; // false
const b = { a: 3 }; // true
const c = { a: 4 }; // true
$lt

Is less than

const query = { a: { $lt: 3 } };

const a = { a: 2 }; // true
const b = { a: 3 }; // false
const c = { a: 4 }; // false
$lte

Is less than or equal to

const query = { a: { $lte: 3 } };

const a = { a: 2 }; // true
const b = { a: 3 }; // true
const c = { a: 4 }; // false
String
$regexp

Matches strings against RegExp

const query = { a: { $regexp: /\w+/g } }

const a = { a: '' }; // false
const b = { a: '0' }; // false
const c = { a: 'a' }; // true
Array
$length

Equal to length

const query = { a: { $length: 3 } }

const a = { a: [] }; // false
const b = { a: [1, 2, 3] }; // true
const c = { a: [1, 2, 3, 4] }; // false
$includes

Has value in array. Does not partial match on arrays or objects.

const query = { a: { $includes: 3 } };

const a = { a: [] }; // false
const b = { a: [1, 2, 3] }; // true

const query = { b: { $includes: [3] } };

const a = { b: [ [3] ] }; // true
const b = { b: [ [3, 4] ] }; // false
Logic
$not

Invert query

const query = { $not: { a: { $lt: 3 } } };

const a = { a: 2 }; // false
const b = { a: 4 }; // true
$and

Must match all queries

const query = { $and: [{ a: 2 }, { b: { $lt: 3 } }] };

const a = { a: 2, b: 2 }; // true
const b = { a: 2, b: 4 }; // false
$or

Matches any query

const query = { $and: [{ a: 2 }, { b: { $lt: 3 } }] };

const a = { a: 2, b: 2 }; // true
const b = { a: 2, b: 4 }; // true

API

id()

Generate a new, unique id with format [timestamp]-[random].

import LeafDB from 'leaf-db';

const id = LeafDB.id();

docs

Get all documents

const docs = db.docs // Doc<T>[]

open()

Open persistent storage.

import LeafDB from 'leaf-db';

const db = new LeafDB();
const corrupted = await db.open({ name: 'db', dir: process.cwd() }); // Corrupt[]

close()

Close persistent storage.

await db.close();

get()

Get document by id

db.get('a'); // { _id: 'a' }

insert()

Insert document(s) into the database. Will throw an error if duplicate _id's are found.

const drafts = [{ name: 'Tulin', }, { name: 'Mipha' }];
// [{ _id: <string>, name: 'Tulin' }, { _id: <string>, name: 'Mipha' }]
const docs = await Promise.all(drafts.map(async draft => draft.insert(draft)));

query()

Find document(s) based by query.

// Return docs where `name` is equal to `Mipha`
const docs = db.query({ name: 'Mipha' });
// Return docs where `name` is equal to `Mipha` or where `name` is equal to `Tulin`
const docs = db.query({ $or: [{ name: 'Mipha' }, { name: 'Tulin' }] });

update()

Update existing document. Throws if document does not exist

// Update document `a` with new name `Tulin`
const docs = db.update({ _id: 'a', name: 'Tulin' });

delete()

Delete document by _id

// Delete document `a`
await db.delete('a');

drop()

Delete all documents in the database.

await db.drop();

Acknowledgements