pocket-db stores everything in a single append-only file — no server, no daemon, no setup. Open a file, work with collections of JSON documents, close. That's the whole model.
SQLite-like deployment + MongoDB-like data model + no native bindings.
Why I built it
I build a lot of personal tools and prototypes: genealogy tracker, expense tracker, file indexer, the odd mini-game, usually in JS/TS. Storage kept getting in the way: a big in-memory JSON blob gets slow and unreliable to rewrite as it grows, and SQLite means giving up the schemaless flexibility that makes JS good for fast iteration. Neither fit, so I built the thing I actually wanted: never reserialize the whole file on write, survive a process being killed mid-operation, and still feel like working with plain JS objects.
How it works
The one hard rule: never reserialize the whole file. Every insert, update, or delete is a sequential append. In-memory state is just indexes, rebuilt by replaying the log on open.
import { pocketDb } from "@axfab/pocket-db";
const db = pocketDb("./data.pdb");
const users = db.collection("users");
users.insertOne({ name: "Ada", role: "admin", age: 37 });
const admins = users.find({ role: "admin", age: { $gte: 18 } }).toArray();
db.close();
Key features
- Single file, zero server, zero daemon
- MongoDB-style query/update operators (
$gte, $in, $set, $push, and more)
- Zero runtime dependencies - pure TypeScript, no native bindings, no node-gyp
- Crash-safe batches: a partial
insertMany/updateMany is discarded on the next open, never half-applied
- Secondary indexes (string/number) with automatic query planning
- Optional
durability: "strict" for fsync-on-every-write
The honest tradeoff
Writes are genuinely fast; competitive with in-memory SQLite for inserts, and faster than every file-backed store I benchmarked for deletes and single-document updates, because a mutation is just one sequential append. Reads are the weak point: there's no document cache yet by default, so every read seeks to disk. On a 1,000-document benchmark, pocket-db's reads land noticeably behind SQLite on disk. A hot-document cache just shipped as a first step; closing that gap without giving up the append-only model is where most of my time goes now.
Good fit: desktop apps, CLI tools, Electron apps, local servers, offline-first prototypes.
Not a fit: multiple concurrent writers, heavy aggregation pipelines, anything that really calls for a server database.
The companion app
I'm also building pocket-desk, a small Electron/Vue3 GUI to browse and query .pdb files, MongoDB Compass-style. It's newer and rougher than pocket-db itself (most of the first pass was AI-assisted and hasn't had the same review yet), but it's already useful for poking at a database without rewriting extra code.
Get involved
MIT-licensed, install with npm install @axfab/pocket-db. It's early (v0.1.x, solo project) - I'm specifically looking for feedback on the storage model and the read-performance gap.
What would make this useful for something you're building?
Repo: https://github.com/AxFab/pocket-db
Docs & benchmarks: https://pocket-db.axfab.net
npm: https://www.npmjs.com/package/@axfab/pocket-db