Overview
The graph corner is Rust's thinnest storage shelf — no vendor-official Neo4j driver exists, and the JVM's TinkerPop gravity (Java's note) has no Rust pole. What works: neo4rs, the community Bolt-protocol driver Neo4j's own docs point at; gremlin-client for TinkerPop stores; and — the corner's genuine bright spot — oxigraph, an embeddable RDF triple store with SPARQL, written in Rust, usable as a library the way sled or SQLite are. When the graph lives in Postgres (Apache AGE) the relational stack applies instead.
Key points
- neo4rs: async Bolt driver —
Graph::new(uri, user, pass), parameterized Cypher viaquery("…").param("k", v), streamedRowStreamresults, explicit transactions (graph.start_txn()); community-maintained with Neo4j-team involvement, covering the driver essentials without the official drivers' full session/routing sophistication. - Cypher discipline transfers verbatim: parameterize always (injection and plan
cache both),
MATCHshape = index design, transaction functions for retry — the concepts are store-side, see databases & storage systems. - gremlin-client speaks the TinkerPop protocol (JanusGraph, Neptune's Gremlin endpoint): traversal strings or a typed builder subset; maintained but niche — polyglot shops usually keep Gremlin tooling on the JVM where TinkerPop lives.
- oxigraph flips the model: the store is a crate (also a server binary) — in-process SPARQL 1.1 over RocksDB, standards-faithful, ideal for knowledge-graph-shaped features embedded in a service without operating a separate database.
- Neptune from Rust = openCypher/Gremlin over HTTPS with SigV4 signing (aws-sigv4 + reqwest) — workable, hand-assembled.
- Honest guidance: for a graph-centric product on Neo4j, Rust is a viable client but the JVM ecosystem is a generation richer (OGMs, Spring Data Neo4j); for graph-shaped features inside a Rust service, neo4rs or embedded oxigraph carry their weight — and recursive CTEs in Postgres remain the right first question, as everywhere.
Examples
let graph = Graph::new("bolt://localhost:7687", "neo4j", pass).await?;
let mut rows = graph.execute(
query("MATCH (p:Person)-[:REPORTS_TO*1..3]->(m:Person {id: $id})
RETURN p.id AS id, p.name AS name")
.param("id", mgr_id.to_string())
).await?;
while let Some(row) = rows.next().await? {
let name: String = row.get("name")?;
// …
}
Related
- Storage access from Rust — the map — parent map.
- Relational databases from Rust — recursive CTEs: the question to ask before adopting a graph store.
- Databases and other storage systems — when graph models beat relational ones.
- Graph databases from Java and from Go — the counterparts; Java holds the official-driver high ground, Rust holds the embedded-store one.