Showcase · Document database

ZetaDB

A document database written entirely in the language.

Collections of JSON documents with computed fields, maintained aggregates, indexes, atomic batches, snapshots and realtime watches. One static binary, embedded or over HTTP, with no C runtime underneath.

2.03×faster than SQLite at the database work of a durable 10,000-document workflow; 4.01× PostgreSQL, 19.9× MongoDB

Results

Database work 10,000 documents: the ten timed steps (ingest, computed field, maintained totals, aggregates, update 10%, change feed, checkpoint) ms, lower is better
ZetaDB 45.3 ms
SQLite 91.8 ms
PostgreSQL 182 ms
MongoDB 899 ms

2.03× faster than SQLite4.01× faster than PostgreSQL19.9× faster than MongoDB

Whole workflow 10,000 documents, process start to exit ms, lower is better
ZetaDB 56.4 ms
SQLite 101 ms
PostgreSQL 194 ms
MongoDB 910 ms

1.79× faster than SQLite3.44× faster than PostgreSQL16.1× faster than MongoDB

Whole workflow 1,000 documents, process start to exit ms, lower is better
ZetaDB 9.4 ms
SQLite 20.8 ms
PostgreSQL 75.9 ms
MongoDB 127 ms

2.20× faster than SQLite8.05× faster than PostgreSQL13.5× faster than MongoDB

Ingest 10,000 documents in one atomic, durable batch ms, lower is better
ZetaDB 26.0 ms
SQLite 42.0 ms
PostgreSQL 102 ms
MongoDB 676 ms

1.61× faster than SQLite3.91× faster than PostgreSQL26.0× faster than MongoDB

Update Replace 1,000 of 10,000 documents in one durable batch ms, lower is better
ZetaDB 3.9 ms
SQLite 6.5 ms
PostgreSQL 11.4 ms
MongoDB 67.9 ms

1.68× faster than SQLite2.95× faster than PostgreSQL17.6× faster than MongoDB

Aggregate Group 10,000 documents by customer, from the source µs, lower is better
ZetaDB 59.45 µs
PostgreSQL 2,201 µs
MongoDB 3,286 µs
SQLite 5,609 µs

37.0× lower than PostgreSQL55.3× lower than MongoDB94.4× lower than SQLite

Maintained totals Read the per-customer totals after the update µs, lower is better
ZetaDB 7.83 µs
SQLite 38.72 µs
PostgreSQL 73.40 µs
MongoDB 332 µs

4.95× lower than SQLite9.37× lower than PostgreSQL42.3× lower than MongoDB

Change feed Read all 11,000 change events ms, lower is better
ZetaDB 8.8 ms
PostgreSQL 20.0 ms
SQLite 24.4 ms
MongoDB 106 ms

2.28× faster than PostgreSQL2.78× faster than SQLite12.1× faster than MongoDB

Reopen New process: open the database and read the totals ms, lower is better
ZetaDB 2.6 ms
MongoDB 11.5 ms
SQLite 13.0 ms
PostgreSQL 14.8 ms

4.47× faster than MongoDB5.05× faster than SQLite5.75× faster than PostgreSQL

Peak memory 10,000-document workflow: the engine process, plus PostgreSQL's and MongoDB's servers MiB, lower is better
ZetaDB 20.8 MiB
SQLite 21.2 MiB
PostgreSQL 102.7 MiB
MongoDB 335.4 MiB

1.02× less than SQLite4.95× less than PostgreSQL16.2× less than MongoDB

Peak memory 1,000-document workflow MiB, lower is better
ZetaDB 5.63 MiB
SQLite 13.8 MiB
PostgreSQL 65.0 MiB
MongoDB 300.7 MiB

2.44× less than SQLite11.5× less than PostgreSQL53.4× less than MongoDB

x86-64 Linux, one pinned AMD EPYC Genoa vCPU for every engine · Vultr dedicated 2 vCPU, Ubuntu 24.04, Linux 6.8 · 31 October 2026 · bench/common/run.py

Medians of 5 runs after a warm-up, with a fresh database for every run. Every engine, servers included, ran on the same pinned CPU, and every answer was checked against a model before its time counted. SQLite 3.46.1 used WAL mode with synchronous=FULL; PostgreSQL 16.15 used synchronous commits; MongoDB 8.0.34 ran as a one-node replica set (change streams need one) with journaled writes. Each engine used its own idiomatic features: generated columns and triggers in SQLite and PostgreSQL. MongoDB has no stored computed fields or live views, so its totals were refreshed with $merge after each write, inside the write timings. Output goes to a memory-backed file read after the clock stops. Peak memory is the engine process's peak RSS plus, for PostgreSQL and MongoDB, their server processes (PSS) during the run; SQLite runs inside the Go test driver, whose runtime alone takes 10.4 MiB.

What it does

  • Insert, upsert, replace, update and delete, with atomic batches that never publish a partial transaction
  • Computed fields with dependency ordering and checked arithmetic
  • Maintained collections: a $match stage and a final $project or $group, kept up to date with their sources
  • Indexes, snapshots, checkpoints and fast reopen
  • HTTP RPC and resumable realtime watches over server-sent events, with filtered and projected changes
  • A typed client library for applications written in the language

Usage

commands.json
[
  {"op": "create_collection", "collection": "orders"},
  {"op": "define_fields", "collection": "orders",
   "fields": {"total": {"$multiply": ["$qty", "$price"]}}},
  {"op": "insert", "collection": "orders", "key": "one",
   "document": {"qty": 3, "price": 7}},
  {"op": "get", "collection": "orders", "key": "one"},
  {"op": "watch", "collection": "orders", "after": 0}
]
terminal
# embedded: one JSON response per command
$ zetadb ./orders commands.json

# HTTP RPC and realtime watches
$ zetadb-server ./orders 8080