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

stratum-db

v0.1.0

Published

A single-file embedded database with automatic, zero-config version history. SQLite's ergonomics, git's memory.

Readme

Stratum

A single-file database that remembers everything, automatically.

Dragging the Time Machine slider through a database's history in the Stratum web UI, live-updating the data grid and pausing on a named snapshot tag

The Time Machine: drag through your database's full history, live. This is stratum serve, not a mockup — see the 60-second quickstart to run it yourself.

The problem

Every mainstream database shows you the present and makes you fight for the past. On Postgres or MySQL, you bolt on your own audit_log tables, triggers, or SQL:2011 temporal tables — supported unevenly, awkward syntax — just to know what a row looked like yesterday. MongoDB has no native versioning at all; change history is entirely the application's job. DuckDB is brilliant for "what does my data look like right now" and has no concept of "what did it look like then." Purpose-built alternatives like Dolt, XTDB, and Datomic exist, but each asks for a new mental model, a server, or a JVM — none give the "grab one binary, get a file, start querying" experience that made SQLite and DuckDB beloved.

The result: teams either ship without a real audit trail and find out the hard way during a compliance review or a bad migration, or spend months building one from scratch.

The bet: make history a first-class, zero-config default. Every write is versioned automatically. You query the past with the SQL you already know, plus a small set of time-travel verbs. No branches to learn, no server to run, no separate audit table to maintain.

Features

  • Automatic versioning, zero config. Every INSERT/UPDATE/DELETE is captured. Nothing is destructively overwritten unless you explicitly compact or purge history.
  • One file, no server. A Stratum database is a single .strat file, same story as SQLite/DuckDB. stratum serve runs a local web UI when you want one, but it's never required.
  • Time travel with SQL you already know. SELECT * FROM users AS OF 'yesterday' — exact timestamps, relative phrases, snapshot tags, or version ids all work after AS OF.
  • DIFF, HISTORY, BLAME, SNAPSHOT, ROLLBACK as first-class query verbs, not a separate audit table you maintain by hand.
  • A CLI and a local web UI, including a Time Machine scrubber that drags through your database's full history live.
  • Natural-language time parsing via chrono-node — "3 days ago," "last Monday," and ISO timestamps all resolve correctly.

How it compares

Real capability differences as of this writing. Partial support is marked with a caveat, not a false checkmark — verify against each project's current docs before relying on this table for a decision.

| Capability | Stratum | Postgres | DuckDB | MongoDB | Dolt | |---|---|---|---|---|---| | Zero-config automatic versioning | ✅ every write | ❌ requires triggers/extensions (e.g. temporal_tables) | ❌ none by default | ❌ none | ✅ every commit | | Time-travel query (AS OF) | ✅ built-in verb | ⚠️ SQL:2011 temporal tables exist but need explicit PERIOD/history-table setup and are unevenly supported across versions | ⚠️ not in plain DuckDB — DuckLake, a separate extension/storage format you explicitly attach to (ATTACH 'ducklake:...'), adds AT (VERSION => n) / AT (TIMESTAMP => ...) | ❌ none | ✅ AS OF | | Single file, no server for local use | ✅ | ❌ always a server process | ✅ | ❌ always a server process | ⚠️ dolt sql queries a local repo with no server, like sqlite3 — but storage is a .dolt/ repo directory (git-style, content-addressed), not one file; dolt sql-server is opt-in, for remote/multi-client access | | Git-style branching & merge | ❌ not in v1 (see Roadmap) | ❌ | ❌ | ❌ | ✅ core feature | | Built-in blame (who/when changed a cell) | ✅ | ❌ (needs custom audit schema) | ❌ | ❌ | ✅ dolt blame | | SQL surface | SQLite dialect + time-travel verbs | Full Postgres SQL | Full SQL, analytics-focused, great columnar performance | Not SQL (document/aggregation API) | MySQL-compatible SQL | | Analytical (OLAP) query performance | Basic — inherits SQLite's row store | Good for OLTP, not analytics-optimized | Excellent — columnar, built for this | N/A (document workloads) | Basic | | Designed scale | Single-node, embedded, local-first | Scales to large multi-node clusters | Single-node, large local/in-process analytics | Distributed, horizontal scale | Single-node / small server |

Stratum is not trying to win on any row where "single-node embedded tool" isn't the right category — it's trying to be the thing you reach for instead of hand-rolling an audit table on top of Postgres, or instead of standing up Debezium + Kafka for a change log you don't need at that scale.

Install

# npm (recommended — requires Node.js >= 18)
npm install -g stratum-db

# or run without installing
npx stratum-db init mydb

# curl install script (downloads a prebuilt binary, or falls back to npm)
curl -fsSL https://raw.githubusercontent.com/prakriti31/stratum/main/scripts/install.sh | sh

No tagged release exists yet (see .github/workflows/release.yml), so the curl script currently falls through to its npm install -g stratum-db fallback path — that part is real and tested. Once a v*.*.* tag is pushed, CI builds and attaches the prebuilt binaries and the script picks them up automatically. See STATUS.md for the exact state.

60-second quickstart

# create a new database
stratum init mydb
# -> created mydb.strat

# open a REPL against it
stratum shell mydb
stratum> CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER);
stratum> INSERT INTO users (id, name, age) VALUES (1, 'Ada', 30);
stratum> UPDATE users SET age = 31 WHERE id = 1;
stratum> SNAPSHOT users AS 'after-birthday';
stratum> UPDATE users SET age = 99 WHERE id = 1;   -- oops, fat-fingered

stratum> SELECT * FROM users AS OF 'after-birthday';
-- shows age = 31, the mistaken 99 never happened as far as this query is concerned

stratum> BLAME users WHERE id = 1;
-- shows every change to row id=1: old value, new value, who, when

stratum> ROLLBACK users TO 'after-birthday';
-- the live table now matches that snapshot; the bad write is undone, not deleted from history

Or skip the REPL entirely:

stratum query mydb "SELECT * FROM users AS OF '3 days ago'"
stratum serve mydb --port 4321   # local web UI with the Time Machine view

CLI reference

stratum init <name>                          Create a new database (<name>.strat)
stratum shell <db>                           Open an interactive REPL
stratum query <db> "<query>"                 Run a single query and print the result
stratum serve <db> [--port <n>]              Start the local web UI (default port 4321)
stratum snapshot <db> --tag=<name>           Tag the current point in time
stratum rollback <db> --to=<time>            Revert a database (or table) to a point in time
stratum diff <db> --table=<t> --from=<t1> --to=<t2>   Row-level diff between two points in time
stratum blame <db> <table> --where "<expr>"  Change history (who/when) for matching rows
stratum export <db> --table=<t> [--as-of=<t>] --format=<csv|json|sql>   Export table data

Run stratum <command> --help for full flag documentation on any subcommand.

stratum serve has no authentication. It binds to 127.0.0.1 only (not reachable from other machines by default), but anyone with access to that port on your machine has full read/write/rollback access to the database — it's a local admin console, the same trust model as running sqlite3 from a terminal, not a hardened multi-user service. Don't port-forward it onto a shared or public network.

Query grammar — ordinary SQL, plus time-travel verbs, inside shell/query:

SELECT * FROM users WHERE age > 21;                    -- ordinary SQL, unchanged

SELECT * FROM users AS OF '2026-07-01';                 -- exact timestamp
SELECT * FROM users AS OF '3 days ago';                  -- natural language
SELECT * FROM users AS OF 'pre-migration';                -- snapshot tag

DIFF users BETWEEN '2026-01-01' AND NOW;                   -- what changed between two points
HISTORY users WHERE id = 42;                                 -- full change history for matching rows
BLAME users WHERE id = 42;                                    -- who changed what, and when

SNAPSHOT users AS 'pre-migration';                              -- name a point in time
ROLLBACK users TO 'pre-migration';                                -- undo to that point

Run stratum <command> --help for full flag documentation on any subcommand.

Architecture

flowchart TB
    subgraph Interfaces
        CLI["CLI (commander)\nshell / query / snapshot / rollback / diff / blame / export"]
        UI["Web UI (React + Vite)\ntable browser, SQL editor, Time Machine"]
    end

    subgraph Server["stratum serve (express)"]
        API["REST API"]
    end

    subgraph Core["src/core — the versioning engine"]
        Grammar["Query grammar\nAS OF / DIFF / HISTORY / BLAME / SNAPSHOT / ROLLBACK"]
        TimeParse["Time resolution\n(chrono-node: NL phrases, ISO, tags, version ids)"]
        Store["VersionedStore\nwrite-interception layer"]
    end

    subgraph Disk["one .strat file"]
        UserTables["user tables"]
        History["__stratum_history"]
        Snapshots["__stratum_snapshots"]
    end

    CLI --> Grammar
    UI --> API --> Grammar
    Grammar --> TimeParse
    Grammar --> Store
    Store -->|every write| UserTables
    Store -->|every write, mirrored| History
    Grammar -->|SNAPSHOT| Snapshots
    Grammar -.reads.-> UserTables
    Grammar -.reads.-> History
    Grammar -.reads.-> Snapshots

    style Core fill:#1a1a2e,color:#fff
    style Disk fill:#16213e,color:#fff

better-sqlite3 provides storage, transactions, and the SQL engine itself — Stratum does not implement its own WAL or B-tree. The versioning layer is a thin interception point: every write goes through VersionedStore, which performs the underlying SQLite write and appends the corresponding history row(s) in the same transaction. That one __stratum_history table is what powers AS OF, DIFF, HISTORY, and BLAME — there's no separate audit subsystem to keep in sync.

Roadmap

  • [x] Core versioning engine + time-travel query grammar
  • [x] CLI with REPL, natural-language time parsing
  • [x] Web UI: table browser, SQL editor, Time Machine scrubber, diff view, blame popover
  • [ ] npm package + curl-installable prebuilt binaries
  • [ ] Compaction / history-purge tooling for long-lived databases
  • [ ] Hosted, no-install browser playground (future work — not a v1 promise)
  • [ ] Git-style branching (exploratory — not committed)

See STATUS.md for the live, phase-by-phase build state.

Who this is for

  • Compliance-heavy teams (fintech, healthtech) who need to prove "who changed this record and when" for SOC 2 / HIPAA-style reviews.
  • Platform/data teams currently running Debezium + Kafka for a change-data-capture log that's more operational overhead than the problem requires.
  • SaaS products that want an "activity history" or "undo" feature for their own end users without building the versioning layer themselves.
  • ML/data teams who need point-in-time-correct data for reproducible training sets.

These are segments Stratum is being built for, not confirmed customers — feedback from people in these positions is exactly what shapes the roadmap above.

Recipes

Short, runnable walkthroughs of the everyday problems Stratum is for:

Non-goals

Stratum is an embedded, single-node tool in the SQLite/DuckDB category. It is not a distributed database, not built for multi-terabyte scale, and not trying to replace Postgres for high-throughput OLTP. See CLAUDE.md for the full list of non-goals and design constraints.

Contributing

Issues and PRs are welcome. Before sending a PR:

  1. Read CLAUDE.md — in particular, the core invariant that all writes to user tables must go through the versioning layer (src/core). A raw INSERT/UPDATE/DELETE against a user table anywhere else is a correctness bug, not a style nit.
  2. npm install && npm test should pass.
  3. npm run lint && npm run typecheck should be clean.
  4. Keep PRs scoped — one behavior change per PR is easier to review than a bundle.

License

MIT