Repository navigation
Releases
0.1.2
Zanzibar-style permissions that run inside your Python process, on a log that is also your lake.
pip install --upgrade nodusdbThis release ships the same engine as 0.1.1. What is new is the evidence: the first head-to-head benchmark against SpiceDB and OpenFGA, and a run of the "log is the lake" claims against real S3. PyPI now shows the new README.
A fresh permission check is a function call
NodusDB keeps the relationship graph in your process's memory, so a check that must reflect every write so far never leaves it. We measured it against SpiceDB v1.57.0 and OpenFGA v1.22.1 with AuthzBench, on two c5.2xlarge machines in AWS. Every engine first agreed with a reference evaluator on all 50,001 checks. At 560,497 relationships:
| Engine and mode | p50 at 100 checks/s | p50 at 1,000 checks/s | A revoked permission still granted for |
|---|---|---|---|
| NodusDB, in your process | 14 µs | 12 µs | never |
| NodusDB follower, with the write's token | 27 µs | 13 µs | never |
SpiceDB fully_consistent |
4.6 ms | 5.5 s | never |
SpiceDB minimize_latency (its default) |
4.2 ms | 5.4 s | up to 3.5 s |
OpenFGA HIGHER_CONSISTENCY |
3.7 ms | 6.6 s | never |
OpenFGA MINIMIZE_LATENCY (check cache on) |
0.62 ms | 6.3 s | 10.0 s, every time |
At 1,000 checks a second both services used 93 to 100% of the 8-vCPU machine they shared with their Postgres, and their checks queued for seconds. The full tables for three dataset sizes, the CPU traces and every raw result are public in AuthzBench, which also invites the vendors to change its tuning by pull request.
Where NodusDB loses: a follower on another machine learns about writes through the bucket, about 140 ms behind the writer at the median and 0.3 s at worst. A durable write through the writer took 4.4 ms, against about 2 ms for the services. There are no lookup APIs yet, one process writes at a time, and the API is Python only.
The log is the lake
Every write goes into one signed, hash-linked log in your own bucket, and that log is also an Iceberg table, a replica stream and a record of the past. Run end to end against S3:
- "Who could view this document at that moment?" gets the same answer through
as_of(rebuilt from S3 in about 0.25 s, then 1,002 checks in 6 ms) and through a recursive DuckDB query over the Iceberg table. eraseremoved a user from memory in 0.22 ms, andwait_erasedreturned 6.9 s later, once the local directory, the Iceberg files and the bucket were scrubbed. A byte scan found the name in none of the 7 places it had been.
What changed in the package
- No runtime changes. The native library, the Python API, the graph directory format and the Parquet files are the same as 0.1.1.
- The README, the PyPI summary and the keywords now describe the authorization use, with three diagrams and a vision page.
- A security policy with private vulnerability reporting, and issue and pull request templates.
- A test race fixed (D255), and the macOS arm64 wheels now build on
macos-15.
The changelog and docs/benchmarks.md have the details.
0.1.1
A speed release. The native library is 5 times faster on graph inserts and 40 to 50 times faster on lake writes than 0.1.0, with the same directory format, the same Parquet files and the same Python API.
Install: pip install --upgrade nodusdb. It needs Python 3.10 or newer and Linux x86_64 or arm64 (glibc 2.34 or newer), macOS 11 or newer (Intel or Apple silicon), or Windows x86_64.
What was wrong: in 0.1.0 every read and write of native memory went through MemorySegment accessors, which native image compiles to a call of about 300 ns, against under 2 ns on a JVM. Every access now goes through NativeMemory, which uses GraalVM pointers in the native library. It still checks bounds and liveness, so a bad access raises an error and never reads arbitrary memory.
Measured on the development laptop against 0.1.0:
- Graph, 1,000,000 edges: flat inserts 162,689 to 810,031 a second, deletes 137,975 to 807,466, the 3-hop median 27.3 to 11.5 µs.
- Lake, NYC taxi suite: ingest 21,017 to 994,900 rows a second, Arrow batch upserts 25,092 to 2,002,694 a second, a Snappy flush of 250,000 rows 9.924 to 0.231 s, the in-memory sum and average of a million rows 922.6 to 2.6 ms.
- In CI the native library now runs within twice the time of the JVM on every probe, and the speed gate fails above a ratio of 10.
What you can rely on:
- Graph directories written by 0.1.0 open in 0.1.1 and the other way round; the format is unchanged.
- The Parquet files are byte-identical to 0.1.0's. A test compares them with hashes recorded from the old writer.
- The Python API is unchanged.
Known limits: graph inserts are still below an older build that kept the graph in Java arrays (810,031 against 1.06 to 1.30 million a second), and PyArrow still flushes with Snappy about 16% faster. One writer; calls on one handle write one at a time; failover is manual.
The full list of changes is in the CHANGELOG, and the investigation is in docs/designs/engineering-review-native-memory.md.
0.1.0
The first stable release of NodusDB, an embedded relationship graph engine for Python. It runs in your process, with a native library inside the wheel: no server and no Java to install.
Install: pip install nodusdb. It needs Python 3.10 or newer and Linux x86_64 or arm64 (glibc 2.34 or newer), macOS 11 or newer (Intel or Apple silicon), or Windows x86_64.
This is the same code as 0.1.0rc2, which was installed from PyPI and smoke-tested on all five platforms and on Python 3.10 and 3.14 before this release.
What it does:
- A graph with fast edge inserts and deletes, k-hop traversal and set intersection, with optional durability through a write-ahead log and snapshots.
- Typed relationship tuples, schemas and permission checks, including a reachability index for nested groups.
- A signed log shipped to object storage, with followers, restore and takeover.
- Erasure, change watching and time travel (
as_of). - A lakehouse write path that batches upserts and deletes into Parquet.
What you can rely on in 0.1.x, from the README:
- The graph directory format does not change within 0.1.x, so any 0.1.x release opens a directory written by another.
- Directories written by 0.1.0rc1 open only after
nodusdb.upgrade(), which cannot be undone. - The Python API only grows within 0.1.x.
Known limits to read before use:
- The in-memory write path is slower than the figures this project reported on 2026-10-03: about 165 thousand flat inserts per second where the old code reached 1.0 to 1.3 million, and a 3-hop median near 27 microseconds where it was 10.5. The README table holds the figures for this release.
- One writer; calls on one handle run one at a time; failover is manual.
- There are no wheels for Alpine (musl), Linux with glibc older than 2.34, or Windows on ARM yet.
The status is Beta. The full list of changes is in the CHANGELOG.
0.1.0rc2
Release candidate for 0.1.0. It carries everything built since rc1: log shipping to object storage with signed chains, followers, restore and takeover, the reachability index, erasure, change watching and time travel (as_of), and a new set of packaging checks.
Install: pip install nodusdb==0.1.0rc2. It needs Python 3.10 or newer on Linux x86_64 or arm64 (glibc 2.34 or newer), macOS 11 or newer, or Windows x86_64.
What changed in packaging:
- One
py3-nonewheel per platform instead of one per Python version, tested on Python 3.10 to 3.14. Python 3.9 is no longer supported. - The wheels carry the Apache-2.0 license, a NOTICE and the license of the GraalVM runtime, and
nodusdb.__version__. - The native library is built with GraalVM Community Edition and no longer prints JDK warnings to standard error.
- The release workflow checks the tag against the package version and the five wheels before it uploads.
Known limits to read before use:
- The in-memory write path is slower than the figures this project reported on 2026-10-03: about 165 thousand flat inserts per second where the old code reached 1.0 to 1.3 million, and a 3-hop median near 27 microseconds where it was 10.5. The README table now holds the figures for this release.
- One writer; calls on one handle run one at a time; failover is manual.
- Directories written by rc1 open only after
nodusdb.upgrade(), which cannot be undone.
The full list of changes is in the CHANGELOG, and the compatibility promise for 0.1.x is in the README.
v0.1.0rc1 (Alpha Release Candidate)
v0.1.0rc1 (Alpha Release Candidate)
First release candidate of nodusdb, an embedded in-process dynamic graph engine for Python. The API may change before 0.1.0. Install with pip install nodusdb==0.1.0rc1.
Benchmarks
Measured with python/benchmarks/compare.py on one laptop (windows-dev). The run loads 1,000,000 directed edges over 200,000 nodes, deletes 500,000 of them, and runs 200 queries of each kind. Every backend returns identical answers before timing starts.
- 1,246,720 edge inserts per second through the flat
array('q')buffer, and 1,331,386 deletes per second. - 3-hop median 10.5 µs, against 152.0 µs for SQLite with one statement per row. That is about 14 times faster. Against SQLite's batched
executemany(113.7 µs), it is about 11 times faster. - Common-neighbor median 7.1 µs, against 22.5 µs for SQLite. NetworkX was slightly faster on this query (6.6 µs). Treat it as a tie.
These numbers come from one machine. CI checks that the code builds and passes tests on three systems. It does not measure speed.
Added
- Graph engine: sparse-set adjacency, k-hop traversal, common neighbors, and set intersection, in a Java kernel behind a native C ABI and a Python
Graph. - Durability: write-ahead log, checkpoints, and recovery.
syncmode returns only after the write is on disk. - String and UUID keys, mapped to dense ids and kept in a symbol table.
- Lakehouse writes:
LakeTablewith Parquet output (Snappy or uncompressed), plus sums and averages over the active buffer. - Release wheels for Linux, macOS, and Windows, for CPython 3.9 to 3.13.
Fixed
GraphandLakeTablecalls are serialized with a lock, so threads can share one object.- Each OS thread attaches its own GraalVM isolate thread. Before, every object in a process shared one.
Platform constraints
- Linux: wheels are tagged
manylinux_2_34. They need glibc 2.34 or newer: Ubuntu 22.04 and later, Debian 12, RHEL 9. Older distributions cannot install them. - macOS: wheels target 11.0 and later.
- Windows: x86_64 only.
- Python: CPython 3.9 to 3.13. The wheel smoke test runs on CPython 3.12 only. The other versions are built from the same library but not run in CI.
Known limits
- One writer. A C handle must not be used from two threads at once.
- Recovery at 30.6 million edges takes about 22 seconds, nearly all of it loading the snapshot.
- A checkpoint pauses writes while it runs.
- Lake files are not compacted. Iceberg metadata and the Arrow export are not built yet.
