Thanks for your interest in ZenithDB. This document covers how to set up a dev environment, the conventions we follow, and how to land a change.
For non-trivial work (new features, format changes, anything in the five "moat" crates listed below), please open an issue first so we can align on direction before you write code.
- Ground rules
- Development setup
- Build, test, lint
- Where things live
- Coding conventions
- Commit messages
- Pull requests
- Sign-off (DCO)
- Reporting issues
- Security
- License
- Be excellent to each other. We expect respectful, professional interactions.
- Small, focused PRs land faster than large, sprawling ones.
- Discuss design before writing the code for non-trivial changes.
- Tests come with the change, not in a follow-up.
- Public APIs and on-disk formats are stability surfaces — treat changes to them with care and call them out explicitly in the PR.
- Rust 1.87+ (stable). The toolchain is pinned in
rust-toolchain.toml;rustupwill pick it up. protoc3.21+- macOS:
brew install protobuf - Debian/Ubuntu:
sudo apt-get install -y protobuf-compiler
- macOS:
- Optional: Docker +
docker composefor the prod-like stack (Postgres + MinIO). - Optional:
cargo-audit,cargo-deny,cargo-nextestfor parity with CI.
cargo install --locked cargo-audit cargo-deny cargo-nextestgit clone https://github.com/Polarityinc/zenith.git
cd zenithdb
cargo build --workspaceThe first build pulls and compiles a lot — expect 5–10 minutes on a clean machine. Subsequent builds are incremental.
cargo run --release -p zen_cli -- serve --config examples/zenithdb.dev.tomlDefault profile uses SQLite catalog + local-FS object store under ./data/. No external services required.
For a prod-like stack with Postgres + MinIO:
docker compose -f deploy/docker/docker-compose.dev.yml up -d
ZEN_PROFILE=prod-like cargo run --release -p zen_cli -- serveThese four commands are what CI runs. Match them locally before pushing:
cargo fmt --all --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace --all-features
cargo deny checkcargo nextest run --workspace is a faster substitute for cargo test if you have it installed.
The benchmark suite is a first-class part of the project. If your change touches the storage engine, query path, or compactor, please include a before/after run:
# Generate a synthetic corpus and load it.
cargo run --release -p zen_cli -- bench gen --rows 4000000 --output /tmp/corpus.bin
cargo run --release -p zen_cli -- bench load --input /tmp/corpus.bin --target http://localhost:8080
# Run the suite.
cargo run --release -p zen_cli -- bench run --suite all --warmup 30s --duration 60s \
--output bench-results/$(date +%Y%m%d-%H%M%S).json
# Compare against the committed baseline.
cargo run --release -p zen_cli -- bench compare \
--baseline bench-results/baseline.json \
--candidate bench-results/$(date +%Y%m%d-%H%M%S).jsonDon't update bench-results/baseline.json in your PR unless that's the explicit goal of the change — baseline updates are a separate, deliberate step.
The fuzz targets live in fuzz/. They use cargo-fuzz. If you change a parser, codec, or wire format, run the relevant target for a few minutes locally:
cd fuzz
cargo +nightly fuzz run <target> -- -max_total_time=300The workspace is 18 crates under crates/. Five contain the engine's defining work; everything else is supporting infrastructure.
Moat crates — change with care, expect close review:
| Crate | Responsibility |
|---|---|
zen_format |
PAX segment encoder/decoder; FSST/ZSTD/Gorilla/FoR/RLE/dict codecs; footer & offset directory layout. |
zen_compactor |
Streaming k-way merge compactor; enforces row-group-level trace-locality. |
zen_query |
Vectorized scan operator, late materialization, predicate pushdown. |
zen_fts |
Tantivy embedded inline in segments. |
zen_wal |
Object-storage WAL with conditional PUT, queryable on PUT-ack. |
Supporting crates: zen_storage, zen_memtable, zen_catalog, zen_index, zen_jsonpath, zen_vector, zen_compress, zen_server, zen_cli, zen_cluster, zen_auth, zen_crypto, zen_proto, zen_ql, zen_bench, zen_common.
Other top-level directories:
tests/—integration,perf,chaostest suites.fuzz/—cargo-fuzztargets.examples/— runnable sample configs.deploy/— Docker, Helm, Terraform.docs/— operator-facing documentation.proto/— protobuf definitions.
- Formatting:
rustfmtdefaults. Runcargo fmt --allbefore committing. - Lints:
cargo clippy --workspace --all-targets -- -D warningsmust pass. CI rejects new warnings. - Errors: prefer
thiserrorfor library crates,anyhowfor binaries / tests. Don'tunwrap()outside tests; useexpect("…")with a real message if you must. unsafe: rare and well-justified. Everyunsafeblock needs a// SAFETY:comment explaining the invariants.- Public API: anything
pubin a library crate is part of the API surface. Add#[doc]for non-obvious behavior. - Comments: explain why, not what. Don't leave commented-out code behind.
- Dependencies: don't add a new top-level dep without a clear reason; prefer features on existing deps. Update
Cargo.tomlworkspace deps, not the leaf crate'sCargo.toml. - Async: tokio only — no
async-std/smol/ threadpool drift.
We follow a loose Conventional Commits style. The first line is <type>: <imperative summary>, under 72 chars. Common types:
feat:— new featurefix:— bug fixperf:— performance improvement (include numbers in the body)refactor:— non-behavior-changing restructuredocs:— docs onlytest:— tests onlyci:— CI/build onlychore:— dep bumps, tooling
Examples from this repo's history:
perf: vectorized WAL predicate eval + simd-json ingest body parse
perf: streaming k-way merge compactor + ahash hot paths
prod: hardening sprint (auth, TLS, observability, durability, encryption, backup, CI, multi-node)
Body should explain why and any tradeoffs. Reference issues with Refs #123 or Fixes #123.
- Branch off
main. Branch names are loose but<type>/<short-desc>is encouraged (e.g.perf/posting-fts-jsonpath-agg,fix/wal-fsync-put). - Keep it focused. One logical change per PR. If review uncovers a second issue, file it as a follow-up rather than expanding the PR.
- Pass CI locally first —
fmt,clippy,test,deny. Catching these locally is much faster than the CI loop. - Update
CHANGELOG.mdunder## [Unreleased]for any user-visible change. - Update docs — at minimum, public API doc-comments. Update
docs/RUNBOOK.mdif you change operator-facing behavior. - Fill out the PR template.
- Get a green review from a CODEOWNER for the touched paths. The storage / format / WAL / compactor / auth crates have additional required reviewers.
We squash-merge by default. Keep your PR title in good shape because that's what ends up in git log.
We don't ship a pre-commit hook, but if you want one, the simplest version is:
cat > .git/hooks/pre-commit <<'EOF'
#!/bin/sh
cargo fmt --all --check && cargo clippy --workspace --all-targets -- -D warnings
EOF
chmod +x .git/hooks/pre-commitBy contributing to ZenithDB you certify the Developer Certificate of Origin. Add a Signed-off-by: trailer to every commit:
git commit -s -m "fix: …"This adds:
Signed-off-by: Your Name <you@example.com>
Use a real name and the email on your GitHub account.
For bugs and feature requests, please use GitHub Issues with the appropriate template. A good bug report includes:
- ZenithDB version (
zen --version) and git SHA if building from source. - OS / arch.
- Config (with secrets redacted).
- Minimal reproduction.
- Logs at
RUST_LOG=zen=debugif relevant. - What you expected vs. what happened.
For questions and design discussion, use GitHub Discussions.
Do not file security issues as public GitHub issues. See SECURITY.md for the disclosure process.
By contributing to ZenithDB, you agree that your contributions will be licensed under the Apache License 2.0.