oxilite
An Oxigraph-compatible RDF database and SPARQL 1.1 engine that uses SQLite as its storage engine. Same data model, same SPARQL semantics and the same Rust API as Oxigraph, on plain SQL. It runs in-process, on a SQLite library you load at runtime, and on Cloudflare D1.
Website · API docs · Guide and architecture · Changelog and issues
Why oxilite
Oxigraph stores its data in RocksDB, which needs native code and a local filesystem. oxilite keeps Oxigraph's API and swaps the storage for SQLite, so a knowledge graph can live where SQLite already lives:
- Edge databases such as Cloudflare D1, where you can send SQL but cannot install extensions or native libraries.
- Hosts that ship their own SQLite: mobile apps, embedded devices, sandboxes, SQLCipher builds.
- Apps that already use SQLite and want their graph in the same file, backed up with the same tools.
It is fast because it is built around how SQLite runs queries: terms are hashed to 64-bit ids in Rust (writes never read back), small integers live inside the id, every triple pattern is an index-only scan, a whole SPARQL query compiles to one SQL statement, and oxilite's own statistics-driven planner fixes the join order. On the BSBM business-intelligence mix it is faster than Oxigraph. See Performance.
Install
[]
= "0.2" # bundled SQLite (feature `rusqlite`, on by default)
| Feature | Adds |
|---|---|
rusqlite (default) |
Store on a bundled, in-process SQLite |
dylib |
Store::open_with_library: any SQLite ≥ 3.37 loaded from a path at runtime |
d1 |
oxilite::d1::D1Backend for AsyncStore in Rust Cloudflare Workers |
cypher |
store.cypher(…): openCypher over the same data |
reasonable |
materialize_with_reasonable(): in-memory OWL 2 RL with reasonable |
Quick start
use RdfFormat;
use QueryResults;
use Store; // was: use oxigraph::store::Store;
let store = open?; // or Store::new() in memory
store.load_from_reader?;
if let Solutions = store.query?
store.update?;
store.optimize?; // refresh planner statistics after big loads
println!; // the SQL and join order
The modules mirror Oxigraph (model, io, sparql, store), so porting is usually a change of crate name. Oxigraph's own store tests and W3C manifest runner pass against oxilite; the few intentional differences are listed under Compatibility.
Your own SQLite library
// features = ["dylib"]
let store = open_with_library?;
Only the stable C API is bound, so the system SQLite, a vendor build or SQLCipher all work.
Cloudflare D1 (Rust Workers)
// oxilite = { version = "0.2", default-features = false, features = ["d1"] }
use ;
let store = open_existing.await?;
let out = store.query_output.await?;
Every query is one D1 call and every update one atomic batch(). How oxilite fits D1's limits (no UDFs, statement and batch sizes, per-row billing) is in the D1 guide. From TypeScript, use @oxilite/d1.
Reasoning
use ;
// ex:Dog rdfs:subClassOf ex:Animal . ex:rex a ex:Dog .
let opts = QueryOptions ;
let out = store.query_output?; // ex:rex
store.materialize?; // OWL 2 RL closure, SQL rules (D1 too); read with `include_inferred: true`
RDFS and OWL QL entailment are query rewrites against a small schema closure, so queries stay single statements and nothing extra is written.
Cypher
// features = ["cypher"]
use ;
let opts = CypherOptions ;
store.cypher_with?;
let r = store.cypher_with?;
Property graphs are a view of the RDF data, so SPARQL and Cypher see the same graph. See oxilite-cypher.
JSON-LD documents and Verifiable Credentials
// features = ["vc"] (or ["jsonld"] for JSON-LD without the credentials profile)
let vcs = store.credentials?;
let id = vcs.put_credential?; // checked, stored verbatim, RDF in graph <id>
let raw = vcs.get_credential?.unwrap.json; // the exact bytes
let docs = store.jsonld?; // any JSON-LD document
docs.put_document?;
Each document is stored byte for byte, and its RDF goes into a named graph of its own (by default its id), which SPARQL queries. Keys, graphs, contexts and metadata indexes are configurable. See oxilite-jsonld and oxilite-vc.
Versioning and time travel
Create a store with StoreOptions { versioning: Versioning::Log, .. } and every write becomes a commit in an immutable change log. QueryOptions::as_of ("HEAD~1", "#42", "@2026-09-01T12:00:00Z") queries any past version, and SERVICE <oxilite:version/HEAD~1> { … } compares two versions in one query. GRAPH <oxilite:history> reads commits (PROV-O) and changes (oxl:added / oxl:removed) as RDF. Datalog adds at "HEAD~1" / at ?c per atom and commit/added/removed/branch relations, and Cypher takes the same as_of. history, changes, diff, with_commit and purge read and manage the log, and set_versioning raises or lowers an existing store's level. Versioning::Stamped keeps only a store clock and the tick that added each quad, and writes no extra row per quad. See the README.
Full-text search
Create the store with StoreOptions { text_index: true, .. } and match literals with FTS5:
PREFIX oxl: <https://oxilite.dev/ns#>
SELECT ?doc WHERE { ?doc rdfs:label ?label FILTER(oxl:textMatch(?label, "graph data*")) }
Learn more
- How it works: the sans-IO core, the storage schema and what a query compiles to
- Performance: BSBM results against Oxigraph and D1 write costs
- Reasoning and validation, Cypher and property graphs, JSON-LD and Verifiable Credentials
- Design decisions and architecture
The oxilite family
oxilite is an Oxigraph-compatible RDF database and SPARQL 1.1 engine that stores its data in SQLite, so it runs anywhere SQLite runs: in-process, on a system or vendor libsqlite3, on Cloudflare D1 and in Durable Objects. The same data can be queried with SPARQL and openCypher, reasoned over with RDFS / OWL, and validated with SHACL and ShEx. Read the overview on oxilitedb.com and the full guide in the main README.
| Package | What it is for |
|---|---|
oxilite |
The store: a drop-in for oxigraph::store::Store, plus AsyncStore for D1 |
oxilite-core |
The sans-IO core: term encoding, schema, SPARQL → SQL compiler and planner |
oxilite-rusqlite |
In-process backend with a bundled SQLite (the default) |
oxilite-dylib |
Backend that loads your own libsqlite3 at runtime |
oxilite-d1 |
Cloudflare D1 backend for Rust Workers |
oxilite-cypher |
openCypher over the same data, OWL- and SHACL-aware |
oxilite-jsonld |
JSON-LD documents stored verbatim, one named graph each |
oxilite-vc |
Verifiable Credentials: stored under their id, indexed, queryable |
oxilite-reason |
OWL 2 RL materialization with reasonable |
oxilite-validate |
SHACL and ShEx validation with rudof |
oxilite-cli |
The oxilite command and a SPARQL endpoint like oxigraph serve |
@oxilite/node |
Node.js bindings, API of Oxigraph's JS package |
@oxilite/d1 |
Cloudflare D1 and Durable Objects from TypeScript (WebAssembly core) |
@oxilite/common |
RDF/JS terms and shared TypeScript types |
License
Dual-licensed under MIT or Apache-2.0, at your option, like Oxigraph.