Show HN: Minigraf – An embedded, bi-temporal graph database in Rust
Minigraf: A Rust-Powered Embedded Bi-Temporal Graph Database
Minigraf is designed to be the "SQLite of bi-temporal graph databases." It provides a lightweight, self-contained memory system for graph data, specifically tailored for mobile applications, AI agents, and browser-based environments. It combines the power of Datalog queries with the ability to "time travel" through data history.
Quick Links: Try it in your browser | Explore the Time Travel Visualizer
🎯 The Vision
Minigraf aims to provide a single-file embedded solution that eliminates complex setup. Its core capabilities include:
- Datalog Querying: Support for recursive rules and intuitive graph traversal.
- Bi-Temporal History: Ability to query based on both transaction time and valid time.
- Advanced Window Functions: Support for
:over (partition-by ... :order-by ...)with functions likesum,count,min,max,avg,rank, androw-number. - Prepared Statements: Optimize performance by parsing and planning once using
$slottokens, then executing repeatedly. - Universal Embedding: Works across Native, WASM, IoT, and mobile via a single
.graphfile. - Zero-Config: Get started instantly with
Minigraf::open("data.graph").
Understanding Bi-Temporality
In Minigraf, a fact is not just a triple, but a temporal entity. Mathematically, a fact can be represented as:
🧠 Why Datalog?
The developers argue that Datalog is fundamentally superior to SQL-like languages for graph workloads:
- Native Recursion: Multi-hop traversals are a core feature, not a complex add-on.
- Reliability: A smaller specification leads to faster production cycles and fewer bugs.
- Temporal Synergy: Time is treated simply as another dimension within the relations.
- Industry Proven: Built on 40+ years of research and used in systems like XTDB and Datomic.
- Graph-Centric: Facts are stored as Entity-Attribute-Value (EAV), which are essentially edges.
- AI-Ready: Because the grammar is uniform (e.g.,
[?e :attr ?v]) and lacks complexJOINvariants, LLMs can generate accurate queries with very few examples.
🛠️ Installation & Setup
Add the following to your Cargo.toml:
[dependencies]
minigraf = "2.0.2"
Alternatively, use the CLI:
cargo add minigraf
Requirement: You must be using Rust 1.89 or a newer version.
⚠️ Known Issues
Everything is perfect There are some bugs in the current release.
The most critical issue in v2.x is that writing or retracting two values of the same attribute for one entity within a single transaction may result in only one value being read back (Issue #371).
Workaround: Perform a separate call for each value when dealing with multi-valued attributes. Note: v2.x will receive security and integrity patches for 12 months after v3.0.0 is released.
🚀 Quick Start Guide
use minigraf::{Minigraf, OpenOptions, BindValue};
// Initialize a file-backed database
let db = OpenOptions::new().open("my_data.graph")?;
// 1. Insert data (Transact)
db.execute(r#"(transact [
[:alice :person/name "Alice"]
[:alice :person/age 30]
[:alice :friend :bob]
[:bob :person/name "Bob"]
])"#)?;
// 2. Basic Query
db.execute(r#"(query [:find ?friend-name :where [:alice :friend ?friend] [?friend :person/name ?friend-name]])"#)?;
// 3. Temporal Query (As of transaction 1)
db.execute("(query [:find ?age :as-of 1 :where [:alice :person/age ?age]])")?;
// 4. Define Recursive Rules
db.execute(r#"(rule [(reachable ?a ?b) [?a :friend ?b]]) (rule [(reachable ?a ?b) [?a :friend ?m] (reachable ?m ?b)])"#)?;
// 5. Prepared Statements for high performance
let pq = db.prepare("(query [:find ?name :as-of $tx :where [$entity :person/name ?name]])")?;
pq.execute([
("tx", BindValue::TxCount(1)),
("entity", BindValue::Entity(alice_id))
])?;
Running the project:
cargo runLaunches the interactive Datalog REPL.cargo testExecutes the 1,212 test suite.cargo run demos/demo_recursive.txtRuns the recursion demo.
📊 Comparison & Compatibility
Feature Matrix
| Feature | Minigraf | XTDB | Cozo | Neo4j | SQLite |
|---|---|---|---|---|---|
| Query Language | Datalog | Datalog | Datalog | Cypher | SQL |
| Single File | ✅ Yes | ❌ No | ❌ No | ❌ No | ✅ Yes |
| Bi-temporal | ✅ Yes | ✅ Yes | ⚠️ Limited | ❌ No | ❌ No |
| Embedded | ✅ Yes | ✅ Yes | ✅ Yes | ❌ No | ✅ Yes |
| Graph Native | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes | ❌ No |
| Rust | ✅ Yes | ❌ No | Clojure | ✅ Yes | ❌ Java |
| WASM Ready | ✅ Yes | ❌ No | ⚠️ Limited | ❌ No | ✅ Yes |
Platform Support
| Platform | Tier | Package | Install Command |
|---|---|---|---|
| Rust (Native) | 1 | minigraf (crates.io) | cargo add minigraf |
| Python | 1 | minigraf (PyPI) | pip install minigraf |
| Browser WASM | 2* | @minigraf/browser (npm) | npm install @minigraf/browser |
| WASI | 2* | @minigraf/wasi (npm) | npm install @minigraf/wasi |
| Node.js | 2* | minigraf (npm) | npm install minigraf |
| Java/JVM | 2* | minigraf-jvm (Maven) | See Wiki |
| Android | 2* | minigraf-android (.aar) | See Wiki |
*Experimental
🧪 Demos & Exploration
- Temporal Reasoning AI: Check out
github.com/adityamukho/temporal_reasoningto see an AI agent using Minigraf to store, audit, and correct its beliefs. - Visualizer: Use the browser-based tool to scrub through transaction and valid time to see how the graph evolves (e.g., correcting a misrecorded salary).