Minigraf
Embedded graph memory for AI agents, mobile apps, and the browser — the SQLite of bi-temporal graph databases
A tiny, self-contained graph database with Datalog queries and bi-temporal time travel. Think SQLite, but for connected data with full history.
Vision
Minigraf is a single-file embedded graph database that lets you:
- ✅ Query relationships with Datalog - Recursive rules, natural graph traversal
- ✅ Time travel through history - Bi-temporal queries (transaction time + valid time)
- ✅ Window functions -
sum/count/min/max/avg/rank/row-number :over (partition-by … :order-by …)in:findclauses - ✅ Prepared statements - Parse + plan once with
$slotbind tokens, execute thousands of times - ✅ Embed anywhere - Native, WASM, mobile, IoT - one
.graphfile - ✅ Zero configuration - Just
Minigraf::open("data.graph")and you're done
Status: See ROADMAP.md for current phase and what's next.
Why Datalog?
Datalog is fundamentally better for graphs than SQL-like languages:
- Recursive by design - Multi-hop traversals are natural, not an afterthought
- Simpler to implement - Smaller spec = more reliable, faster to production
- Perfect for temporal - Time is just another dimension in relations
- Proven at scale - 40+ years of research, production use (Datomic, XTDB)
- Graph-native - Facts (Entity-Attribute-Value) are literally edges
- LLM-friendly - The small, uniform grammar (
[?e :attr ?v]patterns, no JOIN variants, no subquery nesting) is easy for AI coding assistants to generate correctly from a few examples; the entire language fits in a system prompt
Installation
[]
= "0.21"
Or via cargo:
Quick Start
use ;
// Open or create a file-backed database
let db = new.path.open?;
// Add facts
db.execute?;
// Query with Datalog
let results = db.execute?;
// Explicit transaction — all-or-nothing
let mut tx = db.begin_write?;
tx.execute?;
tx.commit?;
// Time travel — query as of past transaction counter
db.execute?;
// Recursive rule — transitive reachability
db.execute?;
// Prepared statement — parse + plan once, execute many times
use BindValue;
let pq = db.prepare?;
let r1 = pq.execute?;
let r2 = pq.execute?;
Demo
See a working implementation of temporal reasoning with Minigraf at github.com/adityamukho/temporal_reasoning — an AI agent that uses Minigraf's bi-temporal model to store, correct, and audit beliefs.
See the Datalog Reference wiki page for the complete syntax.
Why Minigraf?
No other database offers this combination:
| Feature | Minigraf | XTDB | Cozo | Neo4j | SQLite |
|---|---|---|---|---|---|
| Query Language | Datalog | Datalog | Datalog | Cypher | SQL |
| Single File | ✅ Yes | ❌ No | ❌ No | ❌ No | ✅ Yes |
| Bi-temporal | ✅ Yes | ✅ Yes | ⚠️ Time travel | ❌ No | ❌ No |
| Embedded | ✅ Yes | ✅ Yes | ✅ Yes | ❌ No | ✅ Yes |
| Graph Native | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes | ❌ No |
| Rust | ✅ Yes | ❌ Clojure | ✅ Yes | ❌ Java | ❌ C |
| WASM Ready | ✅ Phase 8.1a/b | ❌ No | ⚠️ Limited | ❌ No | ✅ Yes |
Embedded graph memory for agents, mobile, and the browser — SQLite's simplicity + Datomic's temporal model.
See the Comparison wiki page for detailed analysis including temporal vs. time-series databases.
For AI Agents
Store what an agent believes, retract and correct without losing history, and replay past states to audit decisions. Every fact carries both transaction time (when it was recorded) and valid time (when it was true), so you can reconstruct the exact knowledge state at the moment of any past decision.
Pairs well with vector stores (GraphRAG pattern): the vector store answers "what is similar?"; Minigraf answers "what are the relationships, who recorded them, and what did we believe at time T?"
For Mobile Apps
Offline-first storage with retroactive corrections — the bi-temporal model lets you correct a mis-entered value while preserving the original record. Native Kotlin and Swift bindings ship as an Android .aar (GitHub Packages) and an iOS .xcframework (Swift Package Manager) via UniFFI. No Rust required.
// Android (Kotlin)
val db = MiniGrafDb.open(context.filesDir.absolutePath + "/myapp.graph")
db.execute("""(transact [[:alice :person/name "Alice"] [:alice :person/age 30]])""")
val json = db.execute("(query [:find ?name :where [?e :person/name ?name]])")
// iOS (Swift)
let db = try MiniGrafDb.open(path: docsURL.appendingPathComponent("myapp.graph").path)
try db.execute(datalog: #"(transact [[:alice :person/name "Alice"] [:alice :person/age 30]])"#)
let json = try db.execute(datalog: "(query [:find ?name :where [?e :person/name ?name]])")
See the Mobile Integration wiki section for full setup and usage docs (Gradle config, SPM integration, error handling, threading).
For WASM / Browser
Phase 8.1a complete: IndexedDB backend, wasm-pack packaging. Phase 8.1b complete: server-side WASM via wasm32-wasip1 / WASI (Wasmtime, Wasmer). npm release as @minigraf/core planned for Phase 8.2.
See the Use Cases wiki page for detailed guides on all three targets.
Scope
Minigraf runs as:
- ✅ An embedded library
- ✅ A standalone binary (interactive REPL)
- ✅ A WebAssembly module — browser (
wasm32-unknown-unknown) and server-side WASI (wasm32-wasip1) (Phase 8.1a/b complete)
Minigraf will not be (by design):
- Distributed — no clustering, no sharding, no replication; each agent instance owns its own
.graphfile - Client-server — no network protocol in core
- Billion-node scale — optimised for <1M nodes (like SQLite)
- A time-series database — Minigraf is a temporal database; see Comparison
Roadmap
See ROADMAP.md for the full phase plan, current status, and release strategy.
Performance
Benchmarks on Intel Core i7-1065G7 @ 1.30GHz, 16 GB RAM, Rust 1.92.0. See BENCHMARKS.md for full tables.
| Metric | Result |
|---|---|
| Insert (in-memory, single fact) | ~2.7 µs — flat across 1K–100K facts |
| Insert (file-backed, WAL) | ~3.6 µs — flat across 1K–100K facts |
| Point query at 1M facts | 4.3–4.5 s (O(N) scan; Phase 7 target: predicate pushdown) |
| Open time at 1M facts | 1.31 s (2.4× faster than v5 — indexes no longer loaded into RAM) |
| Peak heap at 1M facts | 1.05 GB (~21% less than v5 — indexes paged in on demand) |
File-backed databases enforce a maximum fact size of 4 080 serialised bytes per fact. In-memory databases have no limit.
Contributing
This is a hobby project with a long-term vision. Read PHILOSOPHY.md and ROADMAP.md before proposing features.
See CONTRIBUTING.md for development setup, code standards, and the PR process.
License
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.