HTTP server
The namidb-server binary opens a NamiDB namespace and exposes it over
a small REST API. It’s the same engine as the embedded
library; all this binary adds is
the HTTP boundary, bearer-token auth, a periodic flush loop, and an
opt-in Bolt listener.
See Install for the
install command (cargo install --path crates/namidb-server) or the
Docker image.
Run
namidb-server \ --store "s3://my-bucket/data?ns=prod®ion=us-east-1" \ --listen 0.0.0.0:8080 \ --auth-token "$NAMIDB_AUTH_TOKEN" \ --flush-interval 30sEvery flag can also be set via env vars (NAMIDB_STORE,
NAMIDB_LISTEN, NAMIDB_AUTH_TOKEN, NAMIDB_FLUSH_INTERVAL,
NAMIDB_BOLT_LISTEN). The --store URI follows the same grammar as
the Python client and the CLI — see Storage
backends.
If you don’t pass --auth-token, the server boots in unauthenticated
mode and prints a loud warning. Don’t expose that port to the public
internet.
Endpoints (v0)
| Method | Path | Auth | Description |
|---|---|---|---|
GET | /v0/health | public | Liveness + manifest version + epoch |
GET | /v0/version | public | Server build version |
POST | /v0/cypher | bearer | Run a Cypher query (read or write) |
POST | /v0/admin/flush | bearer | Force a memtable to L0 SST flush |
POST /v0/cypher
Request:
{ "query": "MATCH (p:Person) WHERE p.age >= $min RETURN p.name AS name", "params": {"min": 18}}Response (read):
{ "columns": ["name"], "rows": [{"name": "Alice"}, {"name": "Bob"}]}Response (write):
{ "columns": ["a"], "rows": [{"a": {"_kind": "node", "id": "...", "label": "Person", "properties": {}}}], "write_outcome": { "nodes_created": 1, "edges_created": 0, "nodes_deleted": 0, "edges_deleted": 0, "properties_set": 0 }}End-to-end curl round-trip
TOKEN=$(openssl rand -hex 32)
namidb-server --store memory://demo --listen 127.0.0.1:8080 --auth-token "$TOKEN" &
curl -s http://127.0.0.1:8080/v0/health | jq .
curl -s -X POST http://127.0.0.1:8080/v0/cypher \ -H "Authorization: Bearer $TOKEN" \ -H 'Content-Type: application/json' \ -d '{"query": "CREATE (a:Person {name: \"Alice\", age: 30}) RETURN a.name AS name"}' \ | jq .
curl -s -X POST http://127.0.0.1:8080/v0/cypher \ -H "Authorization: Bearer $TOKEN" \ -H 'Content-Type: application/json' \ -d '{"query": "MATCH (p:Person) RETURN p.name AS name, p.age AS age"}' \ | jq .Concurrency
namidb-server keeps one WriterSession per process. Writes are
serialised behind a single-writer-per-namespace invariant (RFC-001):
at most one write statement is in flight against the namespace at a
time. Reads no longer take the writer mutex — a snapshot cell
(RFC-021) publishes the latest durable view, multiple readers share it
through an Arc, and a write refreshes the cell after each
commit_batch / flush. The integration test
(crates/namidb-server/tests/concurrent_reads.rs) measures a ~7x
fan-out at 8 readers on a 4-core box.
If you need horizontal scale today, point several namidb-server
processes at the same --store URI. Each one serves reads off the
same manifest version, and only one is allowed to commit writes (the
rest get fenced via epoch CAS).
Periodic flush
--flush-interval (default 30s) controls how often the background
task turns the memtable into L0 SSTs. Set it to 0s to disable the
loop and call POST /v0/admin/flush from cron or a sidecar instead.
Bolt protocol
Pass --bolt-listen 0.0.0.0:7687 (or NAMIDB_BOLT_LISTEN) to expose
a Bolt 4.4 / 5.0 / 5.4 listener alongside the HTTP API. Both
protocols share the same WriterSession, the same auth token, and
the same single-writer-per-namespace invariant.
namidb-server \ --store memory://demo \ --listen 0.0.0.0:8080 \ --bolt-listen 0.0.0.0:7687 \ --auth-token "$NAMIDB_AUTH_TOKEN"from neo4j import GraphDatabasedriver = GraphDatabase.driver("bolt://localhost:7687", auth=("namidb", "$NAMIDB_AUTH_TOKEN"))with driver.session() as s: s.run("CREATE (:Person {name: 'Alice'})") for r in s.run("MATCH (p:Person) RETURN p.name AS name"): print(r["name"])The Bolt username is the literal string namidb; the password is the
same bearer token. See Bolt (Neo4j
drivers) for the driver matrix and
RFC-022
for the wire-level design.
On the roadmap
The server README lists these endpoints as planned but not landed yet:
/v0/cypher/stream— NDJSON streaming for large read result sets./v0/cypher/arrow— an Arrow IPC body for zero-copy DataFrame ingestion./v0/metrics— Prometheus exposition (counters, latency histogram, cache hit rates).
What’s next
- HTTP API — the type mapping reference and JSON envelope details.
- Bolt (Neo4j drivers) — driver compatibility matrix and snippets.
- Docker + MinIO — a full local
stack in one
docker-compose.yml. - Configuration — every env var the server reads at startup.