Performance & Limits
file-json-db is an embedded, file-based database. It shines for small-to-medium datasets and low-to-moderate concurrency. This page describes realistic expectations and how to stay fast.
What it is good at
- Thousands to low tens of thousands of documents per collection
- Equality lookups on indexed fields (O(1) via the in-memory index)
- Simple CRUD from a single Node.js process
- CLI tools, Electron apps, small APIs, prototypes, local caches
What it is not designed for
- Hundreds of thousands or millions of documents
- High-concurrency multi-process writes
- Complex analytical queries over huge data
- Networked multi-client access (there is no server)
Indexes make a big difference
A findOne on an indexed field only loads the part that contains
the document. A full-collection scan without an index reads every part.
// Fast – uses secondary index
users.findOne({ email: 'alice@example.com' });
// Slower – full scan
users.find({ age: { $gte: 30 } }).toArray();
Index every field you frequently look up by exact value (email, username, sku, status, foreign keys, …).
Part size tuning
- Smaller parts (e.g. 64–128 KB) → better isolation of corruption, more files.
- Larger parts (e.g. 1 MB) → fewer files, slightly more data loaded per write.
- Default 256 KB is a solid middle ground for most apps.
const logs = db.collection({
name: 'logs',
maxPartSize: 512 * 1024,
maxRecords: 2000
});
Memory
At any moment a collection keeps in memory:
- The full
index.jsonstructure (idIndex + secondary indexes) - Any part files currently being read or written
Parts that are not needed are not kept. Memory therefore grows mainly with the size of the indexes, not with the total size of all part files.
Concurrency model
Async methods on the same collection are serialized through an in-process lock. Multiple processes writing the same collection concurrently are not safe. For multi-process scenarios use a proper database server or external locking.
Practical tips
- Prefer
findOne+ indexed field overfind().first()when you know there is at most one match. - Use
projectto avoid carrying large unused fields around. - Call
rebuildIndexes()only when necessary (it scans every part). - Keep
pretty: falsein production if you want slightly smaller files and faster writes. - Batch inserts with
insertManyinstead of many individualinsertcalls.