CozoDB
An embeddable, transactional, relational-graph database with Datalog as its query language — designed for algorithm-heavy and graph-centric workloads.
CozoDB is a transactional, relational-graph database written in Rust that uses Datalog as its query language. It can be embedded directly into your application (like SQLite), run as a standalone server, or used via WASM in the browser. Its key differentiator is bringing the expressive power of Datalog — recursive queries, graph traversals, and algorithm primitives — to a practical, embeddable database.
Features
- Datalog query language — a declarative logic programming language well-suited to graph traversal, recursive queries, and constraint solving; more expressive than SQL for many graph workloads
- Relational + graph in one — stores data in regular relations (like SQL tables) but queries can traverse graph edges naturally without JOIN soup
- Embeddable — runs in-process as a Rust library, Python library, Node.js module, or WASM module; no separate server required
- ACID transactions — full transactional guarantees backed by a choice of storage engines
- Multiple storage backends — in-memory, RocksDB (persistent), SQLite, TiKV (distributed)
- Built-in algorithms — shortest path, PageRank, community detection, and other graph algorithms available as first-class query primitives, not afterthoughts
- Fixed rules — define reusable recursive computations (e.g. transitive closure, BFS/DFS) that compose with regular Datalog rules
- Multi-language — official bindings for Rust, Python, Node.js, Java, C, and WASM/browser
Installation
As a standalone server
cargo install cozo-bin
Or download a pre-built binary from the releases page:
# Start the server (HTTP API on port 9070 by default)
cozo-bin server# Debian / Fedora — install via cargo or Docker (see above). Docker works on all Linux distributions.As a Rust library
cargo add cozoPython
pip install pycozoNode.js
npm install cozo-nodeThe Query Language: CozoScript
CozoScript is a dialect of Datalog. Queries are structured as rules — named Horn clauses that derive new facts from existing ones.
Basic queries
# Define a relation and query it
?[name, age] := *person[name, age], age > 30
# Equivalent to: SELECT name, age FROM person WHERE age > 30Graph traversal
# Find all friends of Alice (one hop)
?[friend] := *knows[{from: "Alice", to: friend}]
# Find all people reachable from Alice (transitive closure)
reachable[from, to] := *knows[{from: from, to: to}]
reachable[from, to] := reachable[from, mid], *knows[{from: mid, to: to}]
?[person] := reachable["Alice", person]Built-in graph algorithms
# Shortest path between two nodes
?[path, cost] <~ ShortestPathDijkstra(*road[], "CityA", "CityB")
# PageRank over a graph relation
?[node, rank] <~ PageRank(*links[])
# Connected components
?[node, component] <~ ConnectedComponents(*edges[])
# Betweenness centrality
?[node, centrality] <~ BetweennessCentrality(*edges[])Mutations
# Insert rows
:put person {name: "Alice", age: 30}
:put person {name: "Bob", age: 25}
# Insert a relationship
:put knows {from: "Alice", to: "Bob"}
# Delete
:rm person {name: "Bob"}Using CozoDB from Rust
use cozo::{DbInstance, DataValue, ScriptMutability};
fn main() -> cozo::Result<()> {
// Open an in-memory database
let db = DbInstance::new("mem", "", Default::default())?;
// Create a relation
db.run_script(
":create person {name: String => age: Int}",
Default::default(),
ScriptMutability::Mutable,
)?;
// Insert data
db.run_script(
r#"?[name, age] <- [["Alice", 30], ["Bob", 25]]
:put person {name => age}"#,
Default::default(),
ScriptMutability::Mutable,
)?;
// Query
let result = db.run_script(
"?[name, age] := *person[name, age], age > 20",
Default::default(),
ScriptMutability::Immutable,
)?;
println!("{:?}", result.rows);
Ok(())
}HTTP API (standalone server mode)
When running as a server, CozoDB exposes a simple HTTP API:
# Run a query
curl -X POST http://localhost:9070/text-query \
-H 'Content-Type: application/json' \
-d '{
"script": "?[name, age] := *person[name, age]",
"params": {}
}'When to use CozoDB
CozoDB is the right choice when:
- Your data is naturally graph-shaped (social networks, knowledge graphs, dependency trees, routing)
- You need recursive queries (transitive closure, BFS/DFS, hierarchical data) that are painful to express in SQL
- You want graph algorithms (PageRank, shortest path, community detection) without an external graph processing system
- You want an embeddable database with these capabilities — not a separate graph database server
- You are building a knowledge base, recommendation engine, or rule-based reasoning system
For purely relational workloads without graph traversal, a traditional SQL database is likely a better fit.