Sydradb
an embeddable time series database implementation with an SQL compatible query layer
Install / Use
/learn @theroutercompany/SydradbREADME
sydraDB
SydraDB is a single-node time-series database written in Zig.
Alpha statement
Current alpha focus:
- HTTP ingest
- HTTP range queries
- Market-data truth engine alpha: market schema registration,
ts_nsmarket ingest, derived rollups/signals, and revision-aware post-trade analysis - Compiled sydraQL as the default execution path for the supported subset
- CAS-native snapshot, bundle, verify, clone, fetch/push, fsck, vacuum, and upgrade workflows
- Snapshot/restore via CAS bundles
- PostgreSQL wire protocol preview, including the current simple-query path and preview prepared/extended flow
This is intentionally not a broad PostgreSQL replacement. The current compatibility layer is a narrow alpha bridge: startup/auth flow, simple query execution, and a preview prepared/extended path. COPY, broader catalog emulation, and wider compatibility claims remain out of scope.
Supported contract
- Zig:
0.15.1 - Supported build targets:
x86_64-linux-gnuaarch64-linux-gnux86_64-macosaarch64-macos
- Supported allocator modes:
mimalloc(default)default
- Alpha-only / preview surfaces:
small_pool- PostgreSQL prepared statements / extended protocol through
pgwire
- Explicitly unsupported this cycle:
- 32-bit targets
- Influx LP / Prom remote_write adapters
- full PostgreSQL catalog coverage
- COPY
- migration tooling
Quick start
zig build -Doptimize=ReleaseSafe
./zig-out/bin/sydradb # serve using sydradb.toml
curl -XPOST localhost:8080/api/v1/ingest --data-binary $'{"metric":"requests_total","ts":1694300000,"value":42,"labels":{"service":"api","host":"edge-1"},"kind":"counter","unit":"requests"}\n'
# Allocator modes
zig build # default: mimalloc global allocator
zig build -Dallocator-mode=default # supported Zig allocator path
zig build -Dallocator-mode=small_pool # experimental allocator path
Market-data truth engine alpha
The current trading-facing alpha is definition-driven and keeps the existing single-value storage path underneath:
- Register market families with
POST /api/v1/market/schema/register - Ingest market rows with
POST /api/v1/market/ingest - Register bar policies, rollups, and signals with:
POST /api/v1/bar-policies/registerPOST /api/v1/rollups/registerPOST /api/v1/signals/register
- Inspect derived-runtime health with
GET /api/v1/rollupsandGET /api/v1/signals - Subscribe to signal SSE output with
GET /api/v1/signals/subscribe?name=<signal-id> - Run revision-aware analysis with:
POST /api/v1/analysis/markoutPOST /api/v1/analysis/slippagePOST /api/v1/analysis/quote-quality
Current contract notes:
- Market APIs require
ts_nsand treat it as nanosecond epoch time end-to-end. - Market ingest is schema-validated and fans out each row into sibling exact-series metrics such as
market.trade.priceandmarket.bar.close. - Derived outputs carry provenance labels including
data_revision,definition_id, anddefinition_version. - Native multi-column storage is not implemented yet; that remains a later internal foundation project.
Nix
If you use Nix, this repo includes a flake that pins Zig and provides a dev shell:
# Start a shell with the pinned Zig
nix develop
# Build the package (installs to ./result)
nix build
./result/bin/sydradb serve
Notes
- The flake integrates
mitchellh/zig-overlayand pins Zig0.15.1. - To (re)pin:
nix flake lock --update-input nixpkgs --update-input zig-overlaythen commit the updatedflake.lock. - For a one-shot command that always uses the pinned Zig, use
./scripts/zigw ....
macOS note
On macOS, the global zig on your PATH may fail to link Zig's generated build runner even when Xcode is installed. If that happens, use the repo-pinned toolchain instead of the global one:
# one-shot build with the pinned Zig from the flake
./scripts/zigw build -Doptimize=ReleaseSafe
# or enter the shell explicitly
nix develop -c zig build -Doptimize=ReleaseSafe
Direnv (auto-activate dev shell)
This repository includes an .envrc that loads the pinned Nix dev shell.
- Install direnv and nix-direnv
- Nix:
nix profile install nixpkgs#direnv nixpkgs#nix-direnv - Homebrew:
brew install direnv
- Nix:
- Hook direnv in your shell (e.g., zsh): add
eval "$(direnv hook zsh)"to your shell rc. - Ensure nix-direnv is sourced by direnv (recommended):
- Create
~/.config/direnv/direnvrcwith:source "$HOME/.nix-profile/share/nix-direnv/direnvrc"(or equivalent for your profile).
- Create
- In this repo run:
direnv allow.
From now on, entering the directory will auto‑activate the correct toolchain.
Status
Alpha. The current cycle is a stabilization-and-truthfulness push: make the CAS-backed storage path, compiled sydraQL path, and benchmark/demo surface honest and reproducible before broadening the product contract again.
Benchmarks
The repo now carries three benchmark entrypoints for the v0.4.0 alpha cycle:
zig build bench-alloc -- --ops 10000 --concurrency 4 --series 1
zig build bench-sydraql -- --points-per-series 32 --iterations 5
zig build bench-cas
Scenario definitions live under benchmarks/README.md, benchmarks/alloc/scenarios.json, benchmarks/sydraql/scenarios.json, and benchmarks/cas/scenarios.json.
One checked-in sample run is published in benchmarks/v0.4.0-summary.md.
Demos
The repo also carries four reproducible demo scripts:
bash demos/demo-quickstart.sh
bash demos/demo-sydraql-compiled.sh
bash demos/demo-cas-lifecycle.sh
bash demos/demo-pgwire-preview.sh
zig build demo-smoke
See demos/README.md for the current checklist.
License
Apache-2.0
CLI
./zig-out/bin/sydradb # serve (HTTP): /api/v1/ingest, /api/v1/query/range, /api/v1/query/compare, /api/v1/metrics/find, /api/v1/metrics/health, /api/v1/series/find, /api/v1/labels/values, /api/v1/annotations/write, /api/v1/annotations/query, /api/v1/sydraql, /api/v1/market/schema/register, /api/v1/market/ingest, /api/v1/bar-policies/register, /api/v1/rollups, /api/v1/signals, /api/v1/signals/subscribe, /api/v1/analysis/markout, /api/v1/analysis/slippage, /api/v1/analysis/quote-quality, /api/v1/cas/refs, /api/v1/cas/commits, /api/v1/cas/log, /api/v1/cas/diff, /metrics
./zig-out/bin/sydradb pgwire # PostgreSQL wire protocol preview (simple query + preview prepared flow)
./zig-out/bin/sydradb ingest # read NDJSON from stdin, flush, and exit only after points are queryable
./zig-out/bin/sydradb query <series_id> <start_ts> <end_ts>
./zig-out/bin/sydradb compact # merge small→large segments (v2 stub)
./zig-out/bin/sydradb snapshot <dst_dir> # write a self-contained CAS bundle
./zig-out/bin/sydradb restore <src_dir> # apply a CAS bundle into data_dir
./zig-out/bin/sydradb stats # print simple counters
./zig-out/bin/sydradb cas clone <src_dir> <dst_dir> [--borrow]
./zig-out/bin/sydradb cas fetch-local <src_dir> [--materialize]
./zig-out/bin/sydradb cas push-local <dst_dir> [--borrow]
./zig-out/bin/sydradb cas verify-bundle <bundle_dir>
./zig-out/bin/sydradb cas bundle create <dst_dir> [--since <spec>]
./zig-out/bin/sydradb cas bundle verify <bundle_dir>
./zig-out/bin/sydradb cas bundle apply <bundle_dir>
./zig-out/bin/sydradb cas verify
./zig-out/bin/sydradb cas refs
./zig-out/bin/sydradb cas head [ref]
./zig-out/bin/sydradb cas log [heads/main]
./zig-out/bin/sydradb cas branch <name> [spec]
./zig-out/bin/sydradb cas tag <name> [spec]
./zig-out/bin/sydradb cas delete-ref <ref>
./zig-out/bin/sydradb cas rename-ref <old_ref> <new_ref>
./zig-out/bin/sydradb cas reflog <ref> [limit]
./zig-out/bin/sydradb cas diff <lhs> <rhs>
./zig-out/bin/sydradb cas rollback <spec>
./zig-out/bin/sydradb cas migrate-reftable
./zig-out/bin/sydradb cas upgrade
./zig-out/bin/sydradb cas expire [--materialize-borrowed] [--reflog-expiry-ms <n>] [--checkpoint-expiry-ms <n>]
./zig-out/bin/sydradb cas vacuum [--repair] [--materialize-borrowed] [--reflog-expiry-ms <n>] [--checkpoint-expiry-ms <n>] [--prune-grace-ms <n>]
./zig-out/bin/sydradb cas prune [--dry-run] [--grace-ms <n>]
./zig-out/bin/sydradb cas gc [--apply] [--no-reflogs] [--grace-ms <n>]
./zig-out/bin/sydradb cas fsck [--connectivity-only] [--no-reflogs] [--lost-found] [--repair]
./zig-out/bin/sydradb cas pack
./zig-out/bin/sydradb cas checkout <spec>
./zig-out/bin/sydradb cas export-legacy [spec]
CLI result payloads are written to stdout. Interactive startup summaries stay on stderr and are only emitted when stderr is attached to a TTY.
Config: sydradb.toml
data_dir = "./data"
http_port = 8080
fsync = "interval" # always|interval|none
flush_interval_ms = 2000
memtable_max_bytes = 8388608
mem_limit_bytes = 268435456
auth_token = "" # set non-empty to require Bearer auth on /api/*
enable_influx = false
enable_prom = true
cas_mode = "off" # off|dual_write
metadata_read_mode = "legacy" # legacy|shadow|primary
query_compiler_mode = "compiled" # legacy|shadow|compiled
# Per-namespace TTL
retention.weather = 30
Config notes:
mem_limit_bytesis enforced as a coarse ingest backpressure limit over queued + buffered in-memory points. When the limit is hit, ingest rejects new points and increments/metricsrejection counters./api/*error responses now include JSON fieldserror,code, andstatusso clients can distinguish missing input, unsupported query shapes, descriptor conflicts, and overload conditions.POST /api/v1/ingestnow accepts a telemetry-first envelope usingmetric+labels+ optional desc
