Skip to main content

MarsDB

An embeddable property-graph database with an openCypher query subset: single binary, single file, optional in-memory mode.

$ marsdb :memory:
MarsDB graph database. Enter Cypher statements terminated by `;`. Ctrl-D to exit.
marsdb> CREATE (a:Person {name: 'Alice'})-[:KNOWS]->(b:Person {name: 'Bob'});
marsdb> MATCH (a:Person)-[:KNOWS]->(b:Person) RETURN a.name, b.name;
a.name | b.name
Alice | Bob

Install

CLI — installs the marsdb binary:

cargo install marsdb-cli

Rust library:

cargo add marsdb
let db = marsdb::Database::in_memory()?; // or Database::open("path/to.db")
db.execute("CREATE (a:Person {name: 'Alice'})")?;
let result = db.execute("MATCH (n:Person) RETURN n.name")?;

// Or run a `;`-separated batch, one transaction per statement, one
// QueryResult per statement back:
let results = db.execute_batch("CREATE (a:Person {name: 'Alice'}); CREATE (b:Person {name: 'Bob'})")?;

More: cargo run -p marsdb --example task_tracker (CRUD + aggregation), --example social_graph (variable-length traversal, MATCH...CREATE), or --example params_and_batch ($parameters, execute_batch) — full source in marsdb/examples/. Each also writes an SVG chart of its query result (via plotters) to the current directory.

Python:

pip install marsdb
import marsdb
db = marsdb.Database.in_memory()  # or .open(path)
db.execute("CREATE (a:Person {name: 'Alice'})-[:KNOWS]->(b:Person {name: 'Bob'})")
db.execute("MATCH (n:Person) RETURN n.name")
# -> [{'n.name': 'Alice'}, {'n.name': 'Bob'}]

Prebuilt wheels cover macOS (arm64, x86_64) and Linux (x86_64, manylinux); other platforms install from the source distribution and need a Rust toolchain. To build from source directly:

cd marsdb-python
python3 -m venv .venv && source .venv/bin/activate
pip install maturin && maturin develop

CLI usage

marsdb                                  # in-memory REPL
marsdb mydata.db                        # file-backed REPL
marsdb mydata.db "MATCH (n) RETURN n"   # run one query, exit
marsdb :memory: "..."                   # explicit in-memory, one-shot
marsdb mydata.db "CREATE (a); CREATE (b); MATCH (n) RETURN n"  # ;-separated batch

Architecture

marsdb-storage   thin trait boundary over redb (file + in-memory backends)
marsdb-graph     property graph model, CRUD, KV/adjacency encoding
marsdb-query     openCypher subset: pest grammar -> AST -> IR -> executor
marsdb           embeddable public Rust API (Database::open/in_memory/execute)
marsdb-cli       the `marsdb` binary (REPL + one-shot mode)
marsdb-python    PyO3 bindings, builds via maturin

Storage runs on redb, a pure-Rust single-file MVCC embedded KV engine. Query execution compiles Cypher to a small Gremlin-shaped logical IR (AllNodesScan, NodeByLabelScan, Seed, Expand, VarExpand, Filter) so a future Gremlin frontend can target the same executor. Every Cypher statement runs inside one transaction — a read-only MATCH ... RETURN opens a ReadTransaction (a consistent snapshot that runs alongside other concurrent readers or a concurrent writer without contending for redb's single-writer lock), everything else opens a WriteTransaction, committed or aborted as a whole.

Numbers: BENCHMARKS.md.

Cypher coverage

CREATE, multi-label nodes ((n:Post:Message)), $parameters, backslash-escaped string literals (\' \" \\ \n \r \t \b \f), MATCH/OPTIONAL MATCH, undirected (-[r:TYPE]-) and variable-length ([:TYPE*min..max]) relationship patterns, WHERE, one WITH boundary per statement (projection/rename, its own WHERE/WITH...WHERE/ORDER BY/LIMIT), RETURN/DELETE/DETACH DELETE/SET/MATCH ... CREATE (adds an edge between two already-matched nodes — a node token whose variable is already bound reuses that node instead of creating a new one), multi-key ORDER BY, LIMIT, CASE, the built-in functions coalesce()/toInteger(), and implicit-GROUP-BY aggregation (count()/count(*)/sum()/avg()/min()/max()/collect(), with DISTINCT — inside an aggregate call only; a standalone RETURN DISTINCT result-set modifier doesn't exist yet). Two independent MATCH parts across one WITH boundary (MATCH (a) WITH a MATCH (b) ..., where b's pattern doesn't chain from a) correctly cross-join, carrying a alongside every row b produces. UNWIND <list> AS x (fans a list out into one row per element, cross-joined against existing rows; its own WHERE works without needing a second WITH) — <list> is an inline Cypher-text list literal ([1, 2, 'a', $p]) or a variable bound by a preceding WITH ... collect(...); UNWIND $param where $param itself names a list isn't supported yet (no list-valued parameters — every $param is a single scalar). MERGE <pattern> [ON CREATE SET ...] [ON MATCH SET ...] (match-or-create: tries the pattern as an ordinary MATCH first, creates exactly one new instance if nothing matched) — capped at one relationship hop (MERGE (n:Label {props}) or MERGE (a)-[:TYPE]-> (b)); an unconstrained node pattern that isn't already bound (MERGE (n), no label or property) is rejected rather than matching/creating arbitrarily. Named-path capture (MATCH p = (a)-[:KNOWS]->(b) RETURN p, fixed-hop patterns only) and shortestPath((a)-[:TYPE*..N]-(b)) (real shortest-path search via BFS, not just the first path found — both endpoints must already be matched by a preceding clause), plus length(p) to measure one.

Verified against all 7 of LDBC SNB Interactive's short-read reference queries (IS1-IS7) — see marsdb-query/tests/ldbc_is_queries.rs. Not verified: LDBC's complex queries (IC1-14: the full query set beyond one hand-crafted grouping+WITH...WHERE+ORDER BY+LIMIT+collect() checkpoint — see marsdb-query/tests/smoke.rs), comma-separated patterns within one MATCH/CREATE clause beyond a single linear chain (general cross-joins — different from the cross-join WITH-chaining above, which works), chaining past one WITH boundary, MERGE patterns with more than one relationship hop (whole-pattern atomicity across multiple simultaneously-unbound hops isn't attempted), named-path capture over a variable-length pattern (only shortestPath() tracks the hop-by-hop chain needed to reconstruct a path over *-traversal), or shortestPath() with a minimum hop count greater than 1 (a plain visited-set BFS can't correctly answer "shortest path of at least N hops" for N > 1 without a different algorithm).

Roadmap

  • LIMIT short-circuiting
  • RETURN DISTINCT (result-set-level dedup; DISTINCT inside an aggregate call already works)
  • List-valued $parameters, to unblock UNWIND $items AS x
  • From-scratch storage engine (page format, B-tree, crash recovery) as an alternate marsdb-storage backend, independent of redb
  • Gremlin frontend targeting the existing IR

Testing

cargo test --workspace                                             # ~1s
cargo test -p marsdb-graph --test stress -- --ignored --nocapture  # ~15s, large-scale
cargo bench -p marsdb-graph
cargo bench -p marsdb

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

marsdb-0.4.0.tar.gz (104.5 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

marsdb-0.4.0-cp314-cp314-macosx_11_0_arm64.whl (929.0 kB view details)

Uploaded CPython 3.14macOS 11.0+ ARM64

marsdb-0.4.0-cp314-cp314-macosx_10_12_x86_64.whl (983.2 kB view details)

Uploaded CPython 3.14macOS 10.12+ x86-64

marsdb-0.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.1 MB view details)

Uploaded CPython 3.9manylinux: glibc 2.17+ x86-64

File details

Details for the file marsdb-0.4.0.tar.gz.

File metadata

  • Download URL: marsdb-0.4.0.tar.gz
  • Upload date:
  • Size: 104.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for marsdb-0.4.0.tar.gz
Algorithm Hash digest
SHA256 24437dc49d66495e6cb1aab95adf08a9d96765899bde191fc3c4dbc94d561009
MD5 0eeec7bc39048a4c8791c1ef2f54a0f0
BLAKE2b-256 bdf195e1540eb97e974aecad23a9972776145d7292c8d3ccb02c7086a8b5a905

See more details on using hashes here.

File details

Details for the file marsdb-0.4.0-cp314-cp314-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for marsdb-0.4.0-cp314-cp314-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 cf16598c86c6fda615836eac8c9f2a263ef44d94e7b42d34ac760884e7b847ec
MD5 9ea45d410e94e4c6dd2548a8673a1860
BLAKE2b-256 04e8bb75f3959615e5fa4f64a7850bac4e1b626a7998b06b798fb96c63dbc9a9

See more details on using hashes here.

File details

Details for the file marsdb-0.4.0-cp314-cp314-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for marsdb-0.4.0-cp314-cp314-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 338818e43bec4ce7d8826aff2344831be5d3341cd20e0873655721f9e323df2f
MD5 9750efa286daa15b6aa82351166d7352
BLAKE2b-256 67783d00db68e2144a14899ffde522372dff0c32c45de78154c1a895f337c606

See more details on using hashes here.

File details

Details for the file marsdb-0.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for marsdb-0.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 95571e2ca24c3905031bc54ef7272c5c4a3349b5c7151cdf2d17bf4203b410c6
MD5 2c14949455d593c0bdaca868cc454e21
BLAKE2b-256 98bac27fefd6658bef7017fa73e6d852283155454b8b0267695e979b4cf87d67

See more details on using hashes here.

Release history Release notifications | RSS feed

0.9.1

4 files

0.9.0

4 files

0.8.0

4 files

0.7.1

4 files

0.7.0

4 files

0.6.0

4 files

0.5.0

4 files

This release

0.4.0 This release

4 files

0.3.0

4 files

0.2.0

4 files

0.1.0

3 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page