Repository files navigation

zu (図)

zu is an embedded, in-process property-graph database written in Rust. The name is the Japanese word for diagram or figure, because a graph should be something you can hold: one file, one process, no cluster.

It is columnar, vectorized, and factorized in the DuckDB and Kùzu mold, with one design decision no existing system makes: storage is a first-class trait with three engines sharing one query processor.

  • zu1 is the native engine, a single columnar file with cascading lightweight compression and CSR adjacency, built for latency and scan speed.
  • sqlite stores the graph in an ordinary SQLite database file, for interop and as the differential-testing oracle.
  • s3 is object-storage-native with immutable segments, compare-and-swap manifest commits, and a request accountant that keeps the monthly bill flat.

Sixty seconds

use zudb::{Database, params};fnmain() -> zudb::Result<()>{let db = Database::create("social.zu1")?;letmut conn = db.connect()?;
conn.execute("INSERT (p:person {uid: 1, name: 'ada'})")?;
conn.execute("INSERT (p:person {uid: 2, name: 'grace'})")?;let rows = conn.query_with("MATCH (p:person) WHERE p.uid >= $uid RETURN p.name AS name, p.uid AS uid",&params!{"uid" => 1},)?;for row in rows.iter(){let(name, uid):(&str,i64) = row.get()?;println!("{name} {uid}");}Ok(())}

That is cargo add zudb and the whole program: no server, no schema step, no cluster. create makes the file and open is what you use the second time, because a create that found a database and opened it instead is the call that quietly writes into somebody else's data. The same sixty seconds in Python, import zudb, zudb.connect, .to_pandas(), is in zu-python.

The snippet above is a program in this repository, crates/zu-snippets/examples/sixty-seconds.rs, and a test holds this README to it character for character and then runs it. A quickstart is the most read and least compiled code a project has, which is how it comes to be wrong.

Status

Early. The specification is complete and lives in docs/, starting with the overview. Implementation is tracked by milestone issues: M0 encodings, M1 zu1 read/write, M2 query engine, M3 transactions and sqlite, M4 recursion and WCOJ, M5 s3 engine, M6 polish to v1.0.

Nothing is usable yet. If you need an embedded graph database today, look at the Kùzu forks.

Goals

The full measurable list is in the overview, but the shape of the project is:

  • Hot 1-hop neighborhood reads under 10 µs, LDBC short reads under 1 ms warm.
  • Bulk ingest above 1 M edges/s per core, adjacency at or under 8 bits/edge on reordered social graphs.
  • Fully functional in a 128 MiB memory budget, CLI binary under 15 MiB, 10 GB file opens in under 10 ms.
  • A 1 TB graph served from S3 at 100 QPS for under $40 a month, with a bill that stays flat when traffic spikes.
  • Power-cut safe at every instant on every engine, with a crash-injection harness to prove it.

Layout

crates/zu-common ids, errors, shared constants
crates/zu-encoding lightweight encodings (FastLanes, ALP, FSST, cascades)
crates/zu-storage the GraphStore trait every engine implements
crates/zu-zu1 native single-file engine
crates/zu-sqlite SQLite engine
crates/zu-s3 object-storage engine
crates/zu-query parser, planner, factorized executor
crates/zu the public embedded API (published as zudb)
crates/zu-cli the zu binary
crates/zu-snippets the snippets this README prints, compiled and run
docs/ the specification, byte-level where it matters

The crate is published as zudb because zu is taken on crates.io; the repo, binary, and file extension stay zu.

Clients

This repository holds the engine, the Rust SDK, the CLI, the C ABI and its generated zu.h, and the conformance corpus. Everything that compiles against the frozen C ABI instead of against the engine's internals lives in its own repository, which is ADR 0005 and the reason the list below is not a directory listing.

RepositoryWhat it isTier
zu-cC and C++ developer kit: examples, the header-only C++ wrapper, CMake, vcpkg, Conan, the sanitizer suites. zu.h itself is generated here, in this repository1
zu-pythonzudb on PyPI. PyO3, three wheels per platform1
zu-nodezudb on npm. napi-rs, plus the WASM build, for Node, Bun, Deno, and the browser1
zu-gogithub.com/tamnd/zu-go. cgo, with a purego path1
zu-javadev.zudb on Maven Central. Panama, with a JNI fallback, plus Kotlin and Scala layers1
zu-dotnetZuDb on NuGet. Source-generated P/Invoke, NativeAOT-clean2
zu-kitThe binding kit: generated FFI declarations, corpus runners, a reference binding, the scorecard tool3
zu-webThe documentation site. Two thirds of it is generated from this repository's release artifacts

A tier is a promise, so who answers for each client and what its tier asks of it are published rather than implied: docs/clients/overview.md is the maintainer, the repository and the scorecard of every one of them, rendered from clients.toml and held to the table above.

If a bug reproduces through the zu CLI it belongs here, whichever client you found it through. Every client repository's bug template asks that first, because engine bugs filed in client trackers are the standard way a multi-repository project loses track of them.

Installing

curl -fsSL https://raw.githubusercontent.com/tamnd/zu/main/install.sh | sh # macOS, Linux
irm https://raw.githubusercontent.com/tamnd/zu/main/install.ps1 | iex # Windows
brew install tamnd/tap/zu
scoop install zu
docker run --rm -v "$PWD:/data" ghcr.io/tamnd/zu stat graph.zu1

Each of these lands the same thing: the release archive for your platform, unpacked as an install prefix, so bin/zu arrives with include/zu.h, both library forms, the pkg-config file and the CMake package config beside it. Every one of them fetches the release's SHA256SUMS first and refuses to unpack an archive that is not what it says it is.

There is no release yet, so none of these fetch anything today. They are here, tested and held to the platform table, because the install path is the first thing a user runs and the last thing anybody wants to be writing on release day.

Building

make build # cargo build --workspace --all-features
make test # cargo test --workspace --all-features
make lint # rustfmt check + clippy -D warnings

Requires Rust 1.98 (pinned in rust-toolchain.toml).

License

Apache-2.0. See LICENSE.

About

Embedded property-graph database in Rust: columnar, factorized, three storage engines (a single file, SQLite, S3)

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

zu (図)

zu is an embedded, in-process property-graph database written in Rust. The name is the Japanese word for diagram or figure, because a graph should be something you can hold: one file, one process, no cluster.

It is columnar, vectorized, and factorized in the DuckDB and Kùzu mold, with one design decision no existing system makes: storage is a first-class trait with three engines sharing one query processor.

  • zu1 is the native engine, a single columnar file with cascading lightweight compression and CSR adjacency, built for latency and scan speed.
  • sqlite stores the graph in an ordinary SQLite database file, for interop and as the differential-testing oracle.
  • s3 is object-storage-native with immutable segments, compare-and-swap manifest commits, and a request accountant that keeps the monthly bill flat.

Sixty seconds

use zudb::{Database, params};fnmain() -> zudb::Result<()>{let db = Database::create("social.zu1")?;letmut conn = db.connect()?;
conn.execute("INSERT (p:person {uid: 1, name: 'ada'})")?;
conn.execute("INSERT (p:person {uid: 2, name: 'grace'})")?;let rows = conn.query_with("MATCH (p:person) WHERE p.uid >= $uid RETURN p.name AS name, p.uid AS uid",&params!{"uid" => 1},)?;for row in rows.iter(){let(name, uid):(&str,i64) = row.get()?;println!("{name} {uid}");}Ok(())}

That is cargo add zudb and the whole program: no server, no schema step, no cluster. create makes the file and open is what you use the second time, because a create that found a database and opened it instead is the call that quietly writes into somebody else's data. The same sixty seconds in Python, import zudb, zudb.connect, .to_pandas(), is in zu-python.

The snippet above is a program in this repository, crates/zu-snippets/examples/sixty-seconds.rs, and a test holds this README to it character for character and then runs it. A quickstart is the most read and least compiled code a project has, which is how it comes to be wrong.

Status

Early. The specification is complete and lives in docs/, starting with the overview. Implementation is tracked by milestone issues: M0 encodings, M1 zu1 read/write, M2 query engine, M3 transactions and sqlite, M4 recursion and WCOJ, M5 s3 engine, M6 polish to v1.0.

Nothing is usable yet. If you need an embedded graph database today, look at the Kùzu forks.

Goals

The full measurable list is in the overview, but the shape of the project is:

  • Hot 1-hop neighborhood reads under 10 µs, LDBC short reads under 1 ms warm.
  • Bulk ingest above 1 M edges/s per core, adjacency at or under 8 bits/edge on reordered social graphs.
  • Fully functional in a 128 MiB memory budget, CLI binary under 15 MiB, 10 GB file opens in under 10 ms.
  • A 1 TB graph served from S3 at 100 QPS for under $40 a month, with a bill that stays flat when traffic spikes.
  • Power-cut safe at every instant on every engine, with a crash-injection harness to prove it.

Layout

crates/zu-common ids, errors, shared constants
crates/zu-encoding lightweight encodings (FastLanes, ALP, FSST, cascades)
crates/zu-storage the GraphStore trait every engine implements
crates/zu-zu1 native single-file engine
crates/zu-sqlite SQLite engine
crates/zu-s3 object-storage engine
crates/zu-query parser, planner, factorized executor
crates/zu the public embedded API (published as zudb)
crates/zu-cli the zu binary
crates/zu-snippets the snippets this README prints, compiled and run
docs/ the specification, byte-level where it matters

The crate is published as zudb because zu is taken on crates.io; the repo, binary, and file extension stay zu.

Clients

This repository holds the engine, the Rust SDK, the CLI, the C ABI and its generated zu.h, and the conformance corpus. Everything that compiles against the frozen C ABI instead of against the engine's internals lives in its own repository, which is ADR 0005 and the reason the list below is not a directory listing.

RepositoryWhat it isTier
zu-cC and C++ developer kit: examples, the header-only C++ wrapper, CMake, vcpkg, Conan, the sanitizer suites. zu.h itself is generated here, in this repository1
zu-pythonzudb on PyPI. PyO3, three wheels per platform1
zu-nodezudb on npm. napi-rs, plus the WASM build, for Node, Bun, Deno, and the browser1
zu-gogithub.com/tamnd/zu-go. cgo, with a purego path1
zu-javadev.zudb on Maven Central. Panama, with a JNI fallback, plus Kotlin and Scala layers1
zu-dotnetZuDb on NuGet. Source-generated P/Invoke, NativeAOT-clean2
zu-kitThe binding kit: generated FFI declarations, corpus runners, a reference binding, the scorecard tool3
zu-webThe documentation site. Two thirds of it is generated from this repository's release artifacts

A tier is a promise, so who answers for each client and what its tier asks of it are published rather than implied: docs/clients/overview.md is the maintainer, the repository and the scorecard of every one of them, rendered from clients.toml and held to the table above.

If a bug reproduces through the zu CLI it belongs here, whichever client you found it through. Every client repository's bug template asks that first, because engine bugs filed in client trackers are the standard way a multi-repository project loses track of them.

Installing

curl -fsSL https://raw.githubusercontent.com/tamnd/zu/main/install.sh | sh # macOS, Linux
irm https://raw.githubusercontent.com/tamnd/zu/main/install.ps1 | iex # Windows
brew install tamnd/tap/zu
scoop install zu
docker run --rm -v "$PWD:/data" ghcr.io/tamnd/zu stat graph.zu1

Each of these lands the same thing: the release archive for your platform, unpacked as an install prefix, so bin/zu arrives with include/zu.h, both library forms, the pkg-config file and the CMake package config beside it. Every one of them fetches the release's SHA256SUMS first and refuses to unpack an archive that is not what it says it is.

There is no release yet, so none of these fetch anything today. They are here, tested and held to the platform table, because the install path is the first thing a user runs and the last thing anybody wants to be writing on release day.

Building

make build # cargo build --workspace --all-features
make test # cargo test --workspace --all-features
make lint # rustfmt check + clippy -D warnings

Requires Rust 1.98 (pinned in rust-toolchain.toml).

License

Apache-2.0. See LICENSE.

About

Embedded property-graph database in Rust: columnar, factorized, three storage engines (a single file, SQLite, S3)

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

zu (図)

zu is an embedded, in-process property-graph database written in Rust. The name is the Japanese word for diagram or figure, because a graph should be something you can hold: one file, one process, no cluster.

It is columnar, vectorized, and factorized in the DuckDB and Kùzu mold, with one design decision no existing system makes: storage is a first-class trait with three engines sharing one query processor.

  • zu1 is the native engine, a single columnar file with cascading lightweight compression and CSR adjacency, built for latency and scan speed.
  • sqlite stores the graph in an ordinary SQLite database file, for interop and as the differential-testing oracle.
  • s3 is object-storage-native with immutable segments, compare-and-swap manifest commits, and a request accountant that keeps the monthly bill flat.

Sixty seconds

use zudb::{Database, params};fnmain() -> zudb::Result<()>{let db = Database::create("social.zu1")?;letmut conn = db.connect()?;
conn.execute("INSERT (p:person {uid: 1, name: 'ada'})")?;
conn.execute("INSERT (p:person {uid: 2, name: 'grace'})")?;let rows = conn.query_with("MATCH (p:person) WHERE p.uid >= $uid RETURN p.name AS name, p.uid AS uid",&params!{"uid" => 1},)?;for row in rows.iter(){let(name, uid):(&str,i64) = row.get()?;println!("{name} {uid}");}Ok(())}

That is cargo add zudb and the whole program: no server, no schema step, no cluster. create makes the file and open is what you use the second time, because a create that found a database and opened it instead is the call that quietly writes into somebody else's data. The same sixty seconds in Python, import zudb, zudb.connect, .to_pandas(), is in zu-python.

The snippet above is a program in this repository, crates/zu-snippets/examples/sixty-seconds.rs, and a test holds this README to it character for character and then runs it. A quickstart is the most read and least compiled code a project has, which is how it comes to be wrong.

Status

Early. The specification is complete and lives in docs/, starting with the overview. Implementation is tracked by milestone issues: M0 encodings, M1 zu1 read/write, M2 query engine, M3 transactions and sqlite, M4 recursion and WCOJ, M5 s3 engine, M6 polish to v1.0.

Nothing is usable yet. If you need an embedded graph database today, look at the Kùzu forks.

Goals

The full measurable list is in the overview, but the shape of the project is:

  • Hot 1-hop neighborhood reads under 10 µs, LDBC short reads under 1 ms warm.
  • Bulk ingest above 1 M edges/s per core, adjacency at or under 8 bits/edge on reordered social graphs.
  • Fully functional in a 128 MiB memory budget, CLI binary under 15 MiB, 10 GB file opens in under 10 ms.
  • A 1 TB graph served from S3 at 100 QPS for under $40 a month, with a bill that stays flat when traffic spikes.
  • Power-cut safe at every instant on every engine, with a crash-injection harness to prove it.

Layout

crates/zu-common ids, errors, shared constants
crates/zu-encoding lightweight encodings (FastLanes, ALP, FSST, cascades)
crates/zu-storage the GraphStore trait every engine implements
crates/zu-zu1 native single-file engine
crates/zu-sqlite SQLite engine
crates/zu-s3 object-storage engine
crates/zu-query parser, planner, factorized executor
crates/zu the public embedded API (published as zudb)
crates/zu-cli the zu binary
crates/zu-snippets the snippets this README prints, compiled and run
docs/ the specification, byte-level where it matters

The crate is published as zudb because zu is taken on crates.io; the repo, binary, and file extension stay zu.

Clients

This repository holds the engine, the Rust SDK, the CLI, the C ABI and its generated zu.h, and the conformance corpus. Everything that compiles against the frozen C ABI instead of against the engine's internals lives in its own repository, which is ADR 0005 and the reason the list below is not a directory listing.

RepositoryWhat it isTier
zu-cC and C++ developer kit: examples, the header-only C++ wrapper, CMake, vcpkg, Conan, the sanitizer suites. zu.h itself is generated here, in this repository1
zu-pythonzudb on PyPI. PyO3, three wheels per platform1
zu-nodezudb on npm. napi-rs, plus the WASM build, for Node, Bun, Deno, and the browser1
zu-gogithub.com/tamnd/zu-go. cgo, with a purego path1
zu-javadev.zudb on Maven Central. Panama, with a JNI fallback, plus Kotlin and Scala layers1
zu-dotnetZuDb on NuGet. Source-generated P/Invoke, NativeAOT-clean2
zu-kitThe binding kit: generated FFI declarations, corpus runners, a reference binding, the scorecard tool3
zu-webThe documentation site. Two thirds of it is generated from this repository's release artifacts

A tier is a promise, so who answers for each client and what its tier asks of it are published rather than implied: docs/clients/overview.md is the maintainer, the repository and the scorecard of every one of them, rendered from clients.toml and held to the table above.

If a bug reproduces through the zu CLI it belongs here, whichever client you found it through. Every client repository's bug template asks that first, because engine bugs filed in client trackers are the standard way a multi-repository project loses track of them.

Installing

curl -fsSL https://raw.githubusercontent.com/tamnd/zu/main/install.sh | sh # macOS, Linux
irm https://raw.githubusercontent.com/tamnd/zu/main/install.ps1 | iex # Windows
brew install tamnd/tap/zu
scoop install zu
docker run --rm -v "$PWD:/data" ghcr.io/tamnd/zu stat graph.zu1

Each of these lands the same thing: the release archive for your platform, unpacked as an install prefix, so bin/zu arrives with include/zu.h, both library forms, the pkg-config file and the CMake package config beside it. Every one of them fetches the release's SHA256SUMS first and refuses to unpack an archive that is not what it says it is.

There is no release yet, so none of these fetch anything today. They are here, tested and held to the platform table, because the install path is the first thing a user runs and the last thing anybody wants to be writing on release day.

Building

make build # cargo build --workspace --all-features
make test # cargo test --workspace --all-features
make lint # rustfmt check + clippy -D warnings

Requires Rust 1.98 (pinned in rust-toolchain.toml).

License

Apache-2.0. See LICENSE.

About

Embedded property-graph database in Rust: columnar, factorized, three storage engines (a single file, SQLite, S3)

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

zu (図)

zu is an embedded, in-process property-graph database written in Rust. The name is the Japanese word for diagram or figure, because a graph should be something you can hold: one file, one process, no cluster.

It is columnar, vectorized, and factorized in the DuckDB and Kùzu mold, with one design decision no existing system makes: storage is a first-class trait with three engines sharing one query processor.

  • zu1 is the native engine, a single columnar file with cascading lightweight compression and CSR adjacency, built for latency and scan speed.
  • sqlite stores the graph in an ordinary SQLite database file, for interop and as the differential-testing oracle.
  • s3 is object-storage-native with immutable segments, compare-and-swap manifest commits, and a request accountant that keeps the monthly bill flat.

Sixty seconds

use zudb::{Database, params};fnmain() -> zudb::Result<()>{let db = Database::create("social.zu1")?;letmut conn = db.connect()?;
conn.execute("INSERT (p:person {uid: 1, name: 'ada'})")?;
conn.execute("INSERT (p:person {uid: 2, name: 'grace'})")?;let rows = conn.query_with("MATCH (p:person) WHERE p.uid >= $uid RETURN p.name AS name, p.uid AS uid",&params!{"uid" => 1},)?;for row in rows.iter(){let(name, uid):(&str,i64) = row.get()?;println!("{name} {uid}");}Ok(())}

That is cargo add zudb and the whole program: no server, no schema step, no cluster. create makes the file and open is what you use the second time, because a create that found a database and opened it instead is the call that quietly writes into somebody else's data. The same sixty seconds in Python, import zudb, zudb.connect, .to_pandas(), is in zu-python.

The snippet above is a program in this repository, crates/zu-snippets/examples/sixty-seconds.rs, and a test holds this README to it character for character and then runs it. A quickstart is the most read and least compiled code a project has, which is how it comes to be wrong.

Status

Early. The specification is complete and lives in docs/, starting with the overview. Implementation is tracked by milestone issues: M0 encodings, M1 zu1 read/write, M2 query engine, M3 transactions and sqlite, M4 recursion and WCOJ, M5 s3 engine, M6 polish to v1.0.

Nothing is usable yet. If you need an embedded graph database today, look at the Kùzu forks.

Goals

The full measurable list is in the overview, but the shape of the project is:

  • Hot 1-hop neighborhood reads under 10 µs, LDBC short reads under 1 ms warm.
  • Bulk ingest above 1 M edges/s per core, adjacency at or under 8 bits/edge on reordered social graphs.
  • Fully functional in a 128 MiB memory budget, CLI binary under 15 MiB, 10 GB file opens in under 10 ms.
  • A 1 TB graph served from S3 at 100 QPS for under $40 a month, with a bill that stays flat when traffic spikes.
  • Power-cut safe at every instant on every engine, with a crash-injection harness to prove it.

Layout

crates/zu-common ids, errors, shared constants
crates/zu-encoding lightweight encodings (FastLanes, ALP, FSST, cascades)
crates/zu-storage the GraphStore trait every engine implements
crates/zu-zu1 native single-file engine
crates/zu-sqlite SQLite engine
crates/zu-s3 object-storage engine
crates/zu-query parser, planner, factorized executor
crates/zu the public embedded API (published as zudb)
crates/zu-cli the zu binary
crates/zu-snippets the snippets this README prints, compiled and run
docs/ the specification, byte-level where it matters

The crate is published as zudb because zu is taken on crates.io; the repo, binary, and file extension stay zu.

Clients

This repository holds the engine, the Rust SDK, the CLI, the C ABI and its generated zu.h, and the conformance corpus. Everything that compiles against the frozen C ABI instead of against the engine's internals lives in its own repository, which is ADR 0005 and the reason the list below is not a directory listing.

RepositoryWhat it isTier
zu-cC and C++ developer kit: examples, the header-only C++ wrapper, CMake, vcpkg, Conan, the sanitizer suites. zu.h itself is generated here, in this repository1
zu-pythonzudb on PyPI. PyO3, three wheels per platform1
zu-nodezudb on npm. napi-rs, plus the WASM build, for Node, Bun, Deno, and the browser1
zu-gogithub.com/tamnd/zu-go. cgo, with a purego path1
zu-javadev.zudb on Maven Central. Panama, with a JNI fallback, plus Kotlin and Scala layers1
zu-dotnetZuDb on NuGet. Source-generated P/Invoke, NativeAOT-clean2
zu-kitThe binding kit: generated FFI declarations, corpus runners, a reference binding, the scorecard tool3
zu-webThe documentation site. Two thirds of it is generated from this repository's release artifacts

A tier is a promise, so who answers for each client and what its tier asks of it are published rather than implied: docs/clients/overview.md is the maintainer, the repository and the scorecard of every one of them, rendered from clients.toml and held to the table above.

If a bug reproduces through the zu CLI it belongs here, whichever client you found it through. Every client repository's bug template asks that first, because engine bugs filed in client trackers are the standard way a multi-repository project loses track of them.

Installing

curl -fsSL https://raw.githubusercontent.com/tamnd/zu/main/install.sh | sh # macOS, Linux
irm https://raw.githubusercontent.com/tamnd/zu/main/install.ps1 | iex # Windows
brew install tamnd/tap/zu
scoop install zu
docker run --rm -v "$PWD:/data" ghcr.io/tamnd/zu stat graph.zu1

Each of these lands the same thing: the release archive for your platform, unpacked as an install prefix, so bin/zu arrives with include/zu.h, both library forms, the pkg-config file and the CMake package config beside it. Every one of them fetches the release's SHA256SUMS first and refuses to unpack an archive that is not what it says it is.

There is no release yet, so none of these fetch anything today. They are here, tested and held to the platform table, because the install path is the first thing a user runs and the last thing anybody wants to be writing on release day.

Building

make build # cargo build --workspace --all-features
make test # cargo test --workspace --all-features
make lint # rustfmt check + clippy -D warnings

Requires Rust 1.98 (pinned in rust-toolchain.toml).

License

Apache-2.0. See LICENSE.

About

Embedded property-graph database in Rust: columnar, factorized, three storage engines (a single file, SQLite, S3)

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

zu (図)

zu is an embedded, in-process property-graph database written in Rust. The name is the Japanese word for diagram or figure, because a graph should be something you can hold: one file, one process, no cluster.

It is columnar, vectorized, and factorized in the DuckDB and Kùzu mold, with one design decision no existing system makes: storage is a first-class trait with three engines sharing one query processor.

  • zu1 is the native engine, a single columnar file with cascading lightweight compression and CSR adjacency, built for latency and scan speed.
  • sqlite stores the graph in an ordinary SQLite database file, for interop and as the differential-testing oracle.
  • s3 is object-storage-native with immutable segments, compare-and-swap manifest commits, and a request accountant that keeps the monthly bill flat.

Sixty seconds

use zudb::{Database, params};fnmain() -> zudb::Result<()>{let db = Database::create("social.zu1")?;letmut conn = db.connect()?;
conn.execute("INSERT (p:person {uid: 1, name: 'ada'})")?;
conn.execute("INSERT (p:person {uid: 2, name: 'grace'})")?;let rows = conn.query_with("MATCH (p:person) WHERE p.uid >= $uid RETURN p.name AS name, p.uid AS uid",&params!{"uid" => 1},)?;for row in rows.iter(){let(name, uid):(&str,i64) = row.get()?;println!("{name} {uid}");}Ok(())}

That is cargo add zudb and the whole program: no server, no schema step, no cluster. create makes the file and open is what you use the second time, because a create that found a database and opened it instead is the call that quietly writes into somebody else's data. The same sixty seconds in Python, import zudb, zudb.connect, .to_pandas(), is in zu-python.

The snippet above is a program in this repository, crates/zu-snippets/examples/sixty-seconds.rs, and a test holds this README to it character for character and then runs it. A quickstart is the most read and least compiled code a project has, which is how it comes to be wrong.

Status

Early. The specification is complete and lives in docs/, starting with the overview. Implementation is tracked by milestone issues: M0 encodings, M1 zu1 read/write, M2 query engine, M3 transactions and sqlite, M4 recursion and WCOJ, M5 s3 engine, M6 polish to v1.0.

Nothing is usable yet. If you need an embedded graph database today, look at the Kùzu forks.

Goals

The full measurable list is in the overview, but the shape of the project is:

  • Hot 1-hop neighborhood reads under 10 µs, LDBC short reads under 1 ms warm.
  • Bulk ingest above 1 M edges/s per core, adjacency at or under 8 bits/edge on reordered social graphs.
  • Fully functional in a 128 MiB memory budget, CLI binary under 15 MiB, 10 GB file opens in under 10 ms.
  • A 1 TB graph served from S3 at 100 QPS for under $40 a month, with a bill that stays flat when traffic spikes.
  • Power-cut safe at every instant on every engine, with a crash-injection harness to prove it.

Layout

crates/zu-common ids, errors, shared constants
crates/zu-encoding lightweight encodings (FastLanes, ALP, FSST, cascades)
crates/zu-storage the GraphStore trait every engine implements
crates/zu-zu1 native single-file engine
crates/zu-sqlite SQLite engine
crates/zu-s3 object-storage engine
crates/zu-query parser, planner, factorized executor
crates/zu the public embedded API (published as zudb)
crates/zu-cli the zu binary
crates/zu-snippets the snippets this README prints, compiled and run
docs/ the specification, byte-level where it matters

The crate is published as zudb because zu is taken on crates.io; the repo, binary, and file extension stay zu.

Clients

This repository holds the engine, the Rust SDK, the CLI, the C ABI and its generated zu.h, and the conformance corpus. Everything that compiles against the frozen C ABI instead of against the engine's internals lives in its own repository, which is ADR 0005 and the reason the list below is not a directory listing.

RepositoryWhat it isTier
zu-cC and C++ developer kit: examples, the header-only C++ wrapper, CMake, vcpkg, Conan, the sanitizer suites. zu.h itself is generated here, in this repository1
zu-pythonzudb on PyPI. PyO3, three wheels per platform1
zu-nodezudb on npm. napi-rs, plus the WASM build, for Node, Bun, Deno, and the browser1
zu-gogithub.com/tamnd/zu-go. cgo, with a purego path1
zu-javadev.zudb on Maven Central. Panama, with a JNI fallback, plus Kotlin and Scala layers1
zu-dotnetZuDb on NuGet. Source-generated P/Invoke, NativeAOT-clean2
zu-kitThe binding kit: generated FFI declarations, corpus runners, a reference binding, the scorecard tool3
zu-webThe documentation site. Two thirds of it is generated from this repository's release artifacts

A tier is a promise, so who answers for each client and what its tier asks of it are published rather than implied: docs/clients/overview.md is the maintainer, the repository and the scorecard of every one of them, rendered from clients.toml and held to the table above.

If a bug reproduces through the zu CLI it belongs here, whichever client you found it through. Every client repository's bug template asks that first, because engine bugs filed in client trackers are the standard way a multi-repository project loses track of them.

Installing

curl -fsSL https://raw.githubusercontent.com/tamnd/zu/main/install.sh | sh # macOS, Linux
irm https://raw.githubusercontent.com/tamnd/zu/main/install.ps1 | iex # Windows
brew install tamnd/tap/zu
scoop install zu
docker run --rm -v "$PWD:/data" ghcr.io/tamnd/zu stat graph.zu1

Each of these lands the same thing: the release archive for your platform, unpacked as an install prefix, so bin/zu arrives with include/zu.h, both library forms, the pkg-config file and the CMake package config beside it. Every one of them fetches the release's SHA256SUMS first and refuses to unpack an archive that is not what it says it is.

There is no release yet, so none of these fetch anything today. They are here, tested and held to the platform table, because the install path is the first thing a user runs and the last thing anybody wants to be writing on release day.

Building

make build # cargo build --workspace --all-features
make test # cargo test --workspace --all-features
make lint # rustfmt check + clippy -D warnings

Requires Rust 1.98 (pinned in rust-toolchain.toml).

License

Apache-2.0. See LICENSE.

About

Embedded property-graph database in Rust: columnar, factorized, three storage engines (a single file, SQLite, S3)

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

zu (図)

zu is an embedded, in-process property-graph database written in Rust. The name is the Japanese word for diagram or figure, because a graph should be something you can hold: one file, one process, no cluster.

It is columnar, vectorized, and factorized in the DuckDB and Kùzu mold, with one design decision no existing system makes: storage is a first-class trait with three engines sharing one query processor.

  • zu1 is the native engine, a single columnar file with cascading lightweight compression and CSR adjacency, built for latency and scan speed.
  • sqlite stores the graph in an ordinary SQLite database file, for interop and as the differential-testing oracle.
  • s3 is object-storage-native with immutable segments, compare-and-swap manifest commits, and a request accountant that keeps the monthly bill flat.

Sixty seconds

use zudb::{Database, params};fnmain() -> zudb::Result<()>{let db = Database::create("social.zu1")?;letmut conn = db.connect()?;
conn.execute("INSERT (p:person {uid: 1, name: 'ada'})")?;
conn.execute("INSERT (p:person {uid: 2, name: 'grace'})")?;let rows = conn.query_with("MATCH (p:person) WHERE p.uid >= $uid RETURN p.name AS name, p.uid AS uid",&params!{"uid" => 1},)?;for row in rows.iter(){let(name, uid):(&str,i64) = row.get()?;println!("{name} {uid}");}Ok(())}

That is cargo add zudb and the whole program: no server, no schema step, no cluster. create makes the file and open is what you use the second time, because a create that found a database and opened it instead is the call that quietly writes into somebody else's data. The same sixty seconds in Python, import zudb, zudb.connect, .to_pandas(), is in zu-python.

The snippet above is a program in this repository, crates/zu-snippets/examples/sixty-seconds.rs, and a test holds this README to it character for character and then runs it. A quickstart is the most read and least compiled code a project has, which is how it comes to be wrong.

Status

Early. The specification is complete and lives in docs/, starting with the overview. Implementation is tracked by milestone issues: M0 encodings, M1 zu1 read/write, M2 query engine, M3 transactions and sqlite, M4 recursion and WCOJ, M5 s3 engine, M6 polish to v1.0.

Nothing is usable yet. If you need an embedded graph database today, look at the Kùzu forks.

Goals

The full measurable list is in the overview, but the shape of the project is:

  • Hot 1-hop neighborhood reads under 10 µs, LDBC short reads under 1 ms warm.
  • Bulk ingest above 1 M edges/s per core, adjacency at or under 8 bits/edge on reordered social graphs.
  • Fully functional in a 128 MiB memory budget, CLI binary under 15 MiB, 10 GB file opens in under 10 ms.
  • A 1 TB graph served from S3 at 100 QPS for under $40 a month, with a bill that stays flat when traffic spikes.
  • Power-cut safe at every instant on every engine, with a crash-injection harness to prove it.

Layout

crates/zu-common ids, errors, shared constants
crates/zu-encoding lightweight encodings (FastLanes, ALP, FSST, cascades)
crates/zu-storage the GraphStore trait every engine implements
crates/zu-zu1 native single-file engine
crates/zu-sqlite SQLite engine
crates/zu-s3 object-storage engine
crates/zu-query parser, planner, factorized executor
crates/zu the public embedded API (published as zudb)
crates/zu-cli the zu binary
crates/zu-snippets the snippets this README prints, compiled and run
docs/ the specification, byte-level where it matters

The crate is published as zudb because zu is taken on crates.io; the repo, binary, and file extension stay zu.

Clients

This repository holds the engine, the Rust SDK, the CLI, the C ABI and its generated zu.h, and the conformance corpus. Everything that compiles against the frozen C ABI instead of against the engine's internals lives in its own repository, which is ADR 0005 and the reason the list below is not a directory listing.

RepositoryWhat it isTier
zu-cC and C++ developer kit: examples, the header-only C++ wrapper, CMake, vcpkg, Conan, the sanitizer suites. zu.h itself is generated here, in this repository1
zu-pythonzudb on PyPI. PyO3, three wheels per platform1
zu-nodezudb on npm. napi-rs, plus the WASM build, for Node, Bun, Deno, and the browser1
zu-gogithub.com/tamnd/zu-go. cgo, with a purego path1
zu-javadev.zudb on Maven Central. Panama, with a JNI fallback, plus Kotlin and Scala layers1
zu-dotnetZuDb on NuGet. Source-generated P/Invoke, NativeAOT-clean2
zu-kitThe binding kit: generated FFI declarations, corpus runners, a reference binding, the scorecard tool3
zu-webThe documentation site. Two thirds of it is generated from this repository's release artifacts

A tier is a promise, so who answers for each client and what its tier asks of it are published rather than implied: docs/clients/overview.md is the maintainer, the repository and the scorecard of every one of them, rendered from clients.toml and held to the table above.

If a bug reproduces through the zu CLI it belongs here, whichever client you found it through. Every client repository's bug template asks that first, because engine bugs filed in client trackers are the standard way a multi-repository project loses track of them.

Installing

curl -fsSL https://raw.githubusercontent.com/tamnd/zu/main/install.sh | sh # macOS, Linux
irm https://raw.githubusercontent.com/tamnd/zu/main/install.ps1 | iex # Windows
brew install tamnd/tap/zu
scoop install zu
docker run --rm -v "$PWD:/data" ghcr.io/tamnd/zu stat graph.zu1

Each of these lands the same thing: the release archive for your platform, unpacked as an install prefix, so bin/zu arrives with include/zu.h, both library forms, the pkg-config file and the CMake package config beside it. Every one of them fetches the release's SHA256SUMS first and refuses to unpack an archive that is not what it says it is.

There is no release yet, so none of these fetch anything today. They are here, tested and held to the platform table, because the install path is the first thing a user runs and the last thing anybody wants to be writing on release day.

Building

make build # cargo build --workspace --all-features
make test # cargo test --workspace --all-features
make lint # rustfmt check + clippy -D warnings

Requires Rust 1.98 (pinned in rust-toolchain.toml).

License

Apache-2.0. See LICENSE.

About

Embedded property-graph database in Rust: columnar, factorized, three storage engines (a single file, SQLite, S3)

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

zu (図)

zu is an embedded, in-process property-graph database written in Rust. The name is the Japanese word for diagram or figure, because a graph should be something you can hold: one file, one process, no cluster.

It is columnar, vectorized, and factorized in the DuckDB and Kùzu mold, with one design decision no existing system makes: storage is a first-class trait with three engines sharing one query processor.

  • zu1 is the native engine, a single columnar file with cascading lightweight compression and CSR adjacency, built for latency and scan speed.
  • sqlite stores the graph in an ordinary SQLite database file, for interop and as the differential-testing oracle.
  • s3 is object-storage-native with immutable segments, compare-and-swap manifest commits, and a request accountant that keeps the monthly bill flat.

Sixty seconds

use zudb::{Database, params};fnmain() -> zudb::Result<()>{let db = Database::create("social.zu1")?;letmut conn = db.connect()?;
conn.execute("INSERT (p:person {uid: 1, name: 'ada'})")?;
conn.execute("INSERT (p:person {uid: 2, name: 'grace'})")?;let rows = conn.query_with("MATCH (p:person) WHERE p.uid >= $uid RETURN p.name AS name, p.uid AS uid",&params!{"uid" => 1},)?;for row in rows.iter(){let(name, uid):(&str,i64) = row.get()?;println!("{name} {uid}");}Ok(())}

That is cargo add zudb and the whole program: no server, no schema step, no cluster. create makes the file and open is what you use the second time, because a create that found a database and opened it instead is the call that quietly writes into somebody else's data. The same sixty seconds in Python, import zudb, zudb.connect, .to_pandas(), is in zu-python.

The snippet above is a program in this repository, crates/zu-snippets/examples/sixty-seconds.rs, and a test holds this README to it character for character and then runs it. A quickstart is the most read and least compiled code a project has, which is how it comes to be wrong.

Status

Early. The specification is complete and lives in docs/, starting with the overview. Implementation is tracked by milestone issues: M0 encodings, M1 zu1 read/write, M2 query engine, M3 transactions and sqlite, M4 recursion and WCOJ, M5 s3 engine, M6 polish to v1.0.

Nothing is usable yet. If you need an embedded graph database today, look at the Kùzu forks.

Goals

The full measurable list is in the overview, but the shape of the project is:

  • Hot 1-hop neighborhood reads under 10 µs, LDBC short reads under 1 ms warm.
  • Bulk ingest above 1 M edges/s per core, adjacency at or under 8 bits/edge on reordered social graphs.
  • Fully functional in a 128 MiB memory budget, CLI binary under 15 MiB, 10 GB file opens in under 10 ms.
  • A 1 TB graph served from S3 at 100 QPS for under $40 a month, with a bill that stays flat when traffic spikes.
  • Power-cut safe at every instant on every engine, with a crash-injection harness to prove it.

Layout

crates/zu-common ids, errors, shared constants
crates/zu-encoding lightweight encodings (FastLanes, ALP, FSST, cascades)
crates/zu-storage the GraphStore trait every engine implements
crates/zu-zu1 native single-file engine
crates/zu-sqlite SQLite engine
crates/zu-s3 object-storage engine
crates/zu-query parser, planner, factorized executor
crates/zu the public embedded API (published as zudb)
crates/zu-cli the zu binary
crates/zu-snippets the snippets this README prints, compiled and run
docs/ the specification, byte-level where it matters

The crate is published as zudb because zu is taken on crates.io; the repo, binary, and file extension stay zu.

Clients

This repository holds the engine, the Rust SDK, the CLI, the C ABI and its generated zu.h, and the conformance corpus. Everything that compiles against the frozen C ABI instead of against the engine's internals lives in its own repository, which is ADR 0005 and the reason the list below is not a directory listing.

RepositoryWhat it isTier
zu-cC and C++ developer kit: examples, the header-only C++ wrapper, CMake, vcpkg, Conan, the sanitizer suites. zu.h itself is generated here, in this repository1
zu-pythonzudb on PyPI. PyO3, three wheels per platform1
zu-nodezudb on npm. napi-rs, plus the WASM build, for Node, Bun, Deno, and the browser1
zu-gogithub.com/tamnd/zu-go. cgo, with a purego path1
zu-javadev.zudb on Maven Central. Panama, with a JNI fallback, plus Kotlin and Scala layers1
zu-dotnetZuDb on NuGet. Source-generated P/Invoke, NativeAOT-clean2
zu-kitThe binding kit: generated FFI declarations, corpus runners, a reference binding, the scorecard tool3
zu-webThe documentation site. Two thirds of it is generated from this repository's release artifacts

A tier is a promise, so who answers for each client and what its tier asks of it are published rather than implied: docs/clients/overview.md is the maintainer, the repository and the scorecard of every one of them, rendered from clients.toml and held to the table above.

If a bug reproduces through the zu CLI it belongs here, whichever client you found it through. Every client repository's bug template asks that first, because engine bugs filed in client trackers are the standard way a multi-repository project loses track of them.

Installing

curl -fsSL https://raw.githubusercontent.com/tamnd/zu/main/install.sh | sh # macOS, Linux
irm https://raw.githubusercontent.com/tamnd/zu/main/install.ps1 | iex # Windows
brew install tamnd/tap/zu
scoop install zu
docker run --rm -v "$PWD:/data" ghcr.io/tamnd/zu stat graph.zu1

Each of these lands the same thing: the release archive for your platform, unpacked as an install prefix, so bin/zu arrives with include/zu.h, both library forms, the pkg-config file and the CMake package config beside it. Every one of them fetches the release's SHA256SUMS first and refuses to unpack an archive that is not what it says it is.

There is no release yet, so none of these fetch anything today. They are here, tested and held to the platform table, because the install path is the first thing a user runs and the last thing anybody wants to be writing on release day.

Building

make build # cargo build --workspace --all-features
make test # cargo test --workspace --all-features
make lint # rustfmt check + clippy -D warnings

Requires Rust 1.98 (pinned in rust-toolchain.toml).

License

Apache-2.0. See LICENSE.

About

Embedded property-graph database in Rust: columnar, factorized, three storage engines (a single file, SQLite, S3)

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

zu (図)

zu is an embedded, in-process property-graph database written in Rust. The name is the Japanese word for diagram or figure, because a graph should be something you can hold: one file, one process, no cluster.

It is columnar, vectorized, and factorized in the DuckDB and Kùzu mold, with one design decision no existing system makes: storage is a first-class trait with three engines sharing one query processor.

  • zu1 is the native engine, a single columnar file with cascading lightweight compression and CSR adjacency, built for latency and scan speed.
  • sqlite stores the graph in an ordinary SQLite database file, for interop and as the differential-testing oracle.
  • s3 is object-storage-native with immutable segments, compare-and-swap manifest commits, and a request accountant that keeps the monthly bill flat.

Sixty seconds

use zudb::{Database, params};fnmain() -> zudb::Result<()>{let db = Database::create("social.zu1")?;letmut conn = db.connect()?;
conn.execute("INSERT (p:person {uid: 1, name: 'ada'})")?;
conn.execute("INSERT (p:person {uid: 2, name: 'grace'})")?;let rows = conn.query_with("MATCH (p:person) WHERE p.uid >= $uid RETURN p.name AS name, p.uid AS uid",&params!{"uid" => 1},)?;for row in rows.iter(){let(name, uid):(&str,i64) = row.get()?;println!("{name} {uid}");}Ok(())}

That is cargo add zudb and the whole program: no server, no schema step, no cluster. create makes the file and open is what you use the second time, because a create that found a database and opened it instead is the call that quietly writes into somebody else's data. The same sixty seconds in Python, import zudb, zudb.connect, .to_pandas(), is in zu-python.

The snippet above is a program in this repository, crates/zu-snippets/examples/sixty-seconds.rs, and a test holds this README to it character for character and then runs it. A quickstart is the most read and least compiled code a project has, which is how it comes to be wrong.

Status

Early. The specification is complete and lives in docs/, starting with the overview. Implementation is tracked by milestone issues: M0 encodings, M1 zu1 read/write, M2 query engine, M3 transactions and sqlite, M4 recursion and WCOJ, M5 s3 engine, M6 polish to v1.0.

Nothing is usable yet. If you need an embedded graph database today, look at the Kùzu forks.

Goals

The full measurable list is in the overview, but the shape of the project is:

  • Hot 1-hop neighborhood reads under 10 µs, LDBC short reads under 1 ms warm.
  • Bulk ingest above 1 M edges/s per core, adjacency at or under 8 bits/edge on reordered social graphs.
  • Fully functional in a 128 MiB memory budget, CLI binary under 15 MiB, 10 GB file opens in under 10 ms.
  • A 1 TB graph served from S3 at 100 QPS for under $40 a month, with a bill that stays flat when traffic spikes.
  • Power-cut safe at every instant on every engine, with a crash-injection harness to prove it.

Layout

crates/zu-common ids, errors, shared constants
crates/zu-encoding lightweight encodings (FastLanes, ALP, FSST, cascades)
crates/zu-storage the GraphStore trait every engine implements
crates/zu-zu1 native single-file engine
crates/zu-sqlite SQLite engine
crates/zu-s3 object-storage engine
crates/zu-query parser, planner, factorized executor
crates/zu the public embedded API (published as zudb)
crates/zu-cli the zu binary
crates/zu-snippets the snippets this README prints, compiled and run
docs/ the specification, byte-level where it matters

The crate is published as zudb because zu is taken on crates.io; the repo, binary, and file extension stay zu.

Clients

This repository holds the engine, the Rust SDK, the CLI, the C ABI and its generated zu.h, and the conformance corpus. Everything that compiles against the frozen C ABI instead of against the engine's internals lives in its own repository, which is ADR 0005 and the reason the list below is not a directory listing.

RepositoryWhat it isTier
zu-cC and C++ developer kit: examples, the header-only C++ wrapper, CMake, vcpkg, Conan, the sanitizer suites. zu.h itself is generated here, in this repository1
zu-pythonzudb on PyPI. PyO3, three wheels per platform1
zu-nodezudb on npm. napi-rs, plus the WASM build, for Node, Bun, Deno, and the browser1
zu-gogithub.com/tamnd/zu-go. cgo, with a purego path1
zu-javadev.zudb on Maven Central. Panama, with a JNI fallback, plus Kotlin and Scala layers1
zu-dotnetZuDb on NuGet. Source-generated P/Invoke, NativeAOT-clean2
zu-kitThe binding kit: generated FFI declarations, corpus runners, a reference binding, the scorecard tool3
zu-webThe documentation site. Two thirds of it is generated from this repository's release artifacts

A tier is a promise, so who answers for each client and what its tier asks of it are published rather than implied: docs/clients/overview.md is the maintainer, the repository and the scorecard of every one of them, rendered from clients.toml and held to the table above.

If a bug reproduces through the zu CLI it belongs here, whichever client you found it through. Every client repository's bug template asks that first, because engine bugs filed in client trackers are the standard way a multi-repository project loses track of them.

Installing

curl -fsSL https://raw.githubusercontent.com/tamnd/zu/main/install.sh | sh # macOS, Linux
irm https://raw.githubusercontent.com/tamnd/zu/main/install.ps1 | iex # Windows
brew install tamnd/tap/zu
scoop install zu
docker run --rm -v "$PWD:/data" ghcr.io/tamnd/zu stat graph.zu1

Each of these lands the same thing: the release archive for your platform, unpacked as an install prefix, so bin/zu arrives with include/zu.h, both library forms, the pkg-config file and the CMake package config beside it. Every one of them fetches the release's SHA256SUMS first and refuses to unpack an archive that is not what it says it is.

There is no release yet, so none of these fetch anything today. They are here, tested and held to the platform table, because the install path is the first thing a user runs and the last thing anybody wants to be writing on release day.

Building

make build # cargo build --workspace --all-features
make test # cargo test --workspace --all-features
make lint # rustfmt check + clippy -D warnings

Requires Rust 1.98 (pinned in rust-toolchain.toml).

License

Apache-2.0. See LICENSE.

About

Embedded property-graph database in Rust: columnar, factorized, three storage engines (a single file, SQLite, S3)

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages