NEDB Docs / Running it / Wire Protocols

NEDB speaks three protocols natively: its own HTTP/JSON, PostgreSQL's wire protocol, and RESP2. The point of the last two is that your existing tools already speak them — no bespoke client, no driver to write.

HTTP/JSON — the native surface

The daemon (nedbd) serves /v1/databases/*: put/get/query/tx (atomic CAS transactions), TTL, indexes, relations, /verify, Merkle proofs, the Mongo-compatible route, /cast, and /events (SSE). Optional bearer token via NEDBD_TOKEN. Binds loopback by default since v2.2.31 — a hardening fix; expose deliberately or tunnel.

PostgreSQL wire protocol

nedbd --pg-port 5433 opens a real pgwire endpoint — reads and writes. psql, DBeaver, Metabase, Grafana, psycopg, asyncpg and JDBC all work against a tamper-evident store with ordinary SQL:

UPDATE orders SET total = 999 WHERE _id = 'o1';
SELECT total FROM orders WHERE _id = 'o1';                       -- 999
SELECT total FROM orders AS OF SYSTEM TIME 0 WHERE _id = 'o1';   -- 120, forever

Both wire protocols are implemented — simple (psql, psycopg2) and extended Parse/Bind/Describe/Execute (psycopg3, asyncpg, JDBC). Until the extended protocol landed, those frameworks could not run a single query — psycopg3 hung, asyncpg refused. Parameters arrive in text and binary format; a row-capped Execute suspends its portal so a JDBC setFetchSize pages instead of stalling.

Typing without a schema: the type is sampled from the documents already stored — the data is the catalogue. Placeholders in clause positions (AS OF SYSTEM TIME $1) are typed by the grammar; aggregates by meaning (COUNT integer, AVG fractional). A driver that declares types is believed; only unspecified slots are inferred.

Introspection is real SQL: pg_catalog and information_schema are queryable relations synthesised from the live database — \dt is two LEFT JOINs and a nine-branch CASE; \d orders is a regex plus three correlated subqueries. Every psql 17 backslash-describe command exits 0 (tests/test_psql_introspection.py drives the real binary, psql 16 and 17); three exit 1 exactly as on fresh Postgres. Derived values are honest: sizes are blank cells, never invented numbers.

Limits, named: SQL-level cursors (DECLARE/FETCH) are refused by name, not hung. A column with disagreeing stored types advertises text. The connection is cleartext — the endpoint is off without --pg-port, loopback by default; NEDBD_PG_READ_ONLY=1 for never-mutate deployments. Verified by 64 checks in tests/test_pgwire.py driven through psycopg2 — which is libpq.

RESP2

NEDBD_RESP2_PORT=6380 nedbd also speaks RESP2 — redis-cli and redis-benchmark work unchanged, with per-database selection (SELECT shop) and neSQL queries through EVAL:

redis-cli -p 6380 SELECT shop
redis-cli -p 6380 EVAL 'FROM users AS OF 10 WHERE status = "active"' 0
redis-cli -p 6380 EVAL 'FROM beliefs TRACE caused_by' 0