Storage backends
Choose how the TopGun server persists data. The backend is selected at startup via STORAGE_BACKEND (source: packages/server-rust/src/bin/topgun_server.rs:109). Three choices are available: redb (embedded, default), postgres (PostgreSQL, production), and null (ephemeral, tests only).
Choosing a backend
| Scenario | Recommended backend | Reason |
|---|---|---|
| Local development / demo | redb (default) | Zero-config, no Docker, instant start |
| Production — single node | redb or postgres | redb for lowest ops overhead; postgres for shared access |
| Production — multi-node / cluster | postgres | Shared persistence across nodes; redb is per-process |
| Integration tests / CI | null | Ephemeral; deterministic between runs |
redb (embedded default)
redb is the default backend added in SPEC-241. The server opens a single file (./topgun.redb by default) directly in-process. No Postgres, no Docker, no connection pool.
Starting with redb
# Default — no configuration needed
pnpm start:server
# Or with explicit path
TOPGUN_REDB_PATH=/var/lib/topgun/data.redb pnpm start:server Configuration
| Variable | Default | Description |
|---|---|---|
STORAGE_BACKEND | "redb" | Set to redb or omit entirely |
TOPGUN_REDB_PATH | ./topgun.redb | File path for the redb database file |
Source: STORAGE_BACKEND at bin/topgun_server.rs:109; TOPGUN_REDB_PATH at bin/topgun_server.rs:115.
Notes
- Data persists across server restarts as long as the file exists.
- Single-process: not shared between multiple server instances.
- For Docker deployments, mount the path as a volume so data survives container recreation.
PostgreSQL
Starting with PostgreSQL
# Switch to PostgreSQL
STORAGE_BACKEND=postgres \
DATABASE_URL=postgres://user:pass@localhost/myapp \
pnpm start:server TopGun works alongside your existing PostgreSQL database. It creates its own topgun_maps table and never touches your application tables.
What TopGun creates
-- TopGun automatically creates this table on startup
-- Your existing tables are NOT modified
CREATE TABLE IF NOT EXISTS topgun_maps (
map_name TEXT NOT NULL,
key TEXT NOT NULL,
value BYTEA NOT NULL, -- MsgPack-encoded CRDT data
expiration_time BIGINT NOT NULL DEFAULT 0,
is_backup BOOLEAN NOT NULL DEFAULT FALSE,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
PRIMARY KEY (map_name, key, is_backup)
);
-- Index for efficient map-level queries
CREATE INDEX IF NOT EXISTS idx_topgun_maps_map
ON topgun_maps (map_name); Safe coexistence
topgun_ prefix for all its tables. It never creates, modifies, or drops tables outside this namespace. Your existing data is safe.Configuration
| Variable | Default | Description |
|---|---|---|
STORAGE_BACKEND | "redb" | Must be set to postgres to use PostgreSQL |
DATABASE_URL | — | PostgreSQL connection URL (required when STORAGE_BACKEND=postgres) |
Source: STORAGE_BACKEND at bin/topgun_server.rs:109; DATABASE_URL at bin/topgun_server.rs:126.
When to use a separate database
For production, you may want TopGun to use a separate PostgreSQL database to isolate resource usage:
DATABASE_URL=postgres://user:pass@localhost/topgun_data \
STORAGE_BACKEND=postgres \
pnpm start:server
Consider isolation when:
- TopGun write volume is high and you want to isolate I/O
- You want independent backup/restore for TopGun data
- Your existing database is already under heavy load
null (ephemeral, test only)
Test use only
null backend stores nothing to disk. All data is lost when the server stops. Do not use in production.# In-memory ephemeral backend — data lost on restart
# Use in unit tests / CI only
STORAGE_BACKEND=null pnpm start:server The null backend is used in the TopGun integration test suite for deterministic, stateless test runs. Source: bin/topgun_server.rs:109 — "null" is one of the three accepted values.
Tombstone reclamation and legacy stores
When an OR-Map entry is removed, the server keeps a small tombstone so the deletion converges across every replica. Tombstones are reclaimed automatically once every tracked client has synced past them — no operator action is required on a store created by a current server.
Stores first written by a pre-epoch server may still carry a legacy
tombstone corpus in an older on-disk form. That corpus is excluded from
garbage collection by design: it is never eligible for automatic reclamation, so
it can never resurrect a deleted entry. It is inert and safe to leave in place. On
startup the server logs a one-line WARN reporting how many legacy tombstone rows
it found.
The supported way to reclaim a legacy corpus is to recreate the datastore: stop
the server, start it against a fresh store (a new TOPGUN_REDB_PATH, or an empty
PostgreSQL database), and let clients reconnect. Because every client holds its own
authoritative local state, CRDT delta-sync restores the live data on reconnect while
the stale legacy tombstones are simply not recreated. There is intentionally no
in-place “drop legacy tombstones” switch — dropping a tombstone while a client still
holds the matching add is exactly the resurrection hazard the tombstone exists to
prevent.
Switching between backends
Data does not auto-migrate between backends. If you switch from redb to postgres (or vice versa), the server starts with an empty store on the new backend. Clients re-sync their local state on reconnect via MerkleTree delta sync.
Operational notes:
- redb → postgres: Export is not built-in today. For production migrations, re-ingest data from clients (they hold authoritative local state). Standard path: start fresh postgres instance, let clients reconnect and push their local maps.
- postgres → redb:
pg_dumpthetopgun_mapstable if you need a snapshot, then restore using standard SQL tools. TopGun does not provide a migration utility (out of scope; follow standard SQL dump/file-copy procedures). - Backup: For redb, copy the
.redbfile. For postgres, usepg_dump. For cluster deployments, back up the primary postgres instance.