Graphersal
An in-memory graph database and traversal engine in Rust, queried with GQL, the ISO standard graph query language, and with Gremlin, with vector search for GraphRAG.
Playground · Book · Step reference · API docs · Mirror on GitHub Pages
Why Graphersal
AI moves faster than the tools around it. We built Graphersal so you don't have to wait for them: a lightweight, embeddable graph engine you can turn into whatever your AI solution needs — a library inside your application, a tool for your agents, or a full server with your own features on top.
It works out of the box: a browser UI, an MCP endpoint for AI agents, an AI chat where you simply ask about your graph in plain language and it writes and runs the queries for you, durable storage and transactions, and the safety to run queries you did not write — permissions, read-only access, resource limits and timeouts. You start with a working system, not with a list of components to wire together.
Vector search and GraphRAG
Store your embeddings next to the graph and search them in the same query that walks it. A
vector is a value type of its own (f32, or quantized to f16, i8 or bit to save memory),
declared in the schema, searched exactly with nearest() and similarity() (cosine, dot product,
L2, Hamming). GraphRAG in one traversal: find the passages nearest to the question, then follow
the edges to what the graph knows about them, and hand that context to your language model.
// "What should I cook for my cat?" ~ the question's embedding
g.v().has_label("doc").nearest("emb", question, 2)
.project("title", "author", "topic")
.by("title")
.by(__.in("wrote").values("name"))
.by(__.out("about").values("name"))
Run it in the playground
with toy embeddings, no model needed. Graphersal can also make the embeddings itself: the
embed() step and embed_property() turn text into vectors with the built-in hash-ngram/1, a
local Model2Vec model
(graphersal embed-model download minishlab/potion-base-8M, then --embedder) or any model you
register from Rust or Python; the schema records which model made each property, so a text query
such as nearest("emb", "what should I cook for my cat?", 2) uses the right one. Or bring vectors
from the provider of your choice: Graphersal stores, filters and searches them, in the browser, in
your Rust application, from Python and through MCP. The guide:
Embeddings and Vector Search.
A first look
You ask Graphersal questions in plain language, in GQL or in Gremlin. In the AI chat you simply write what you want to know, and the model of your choice turns it into queries, runs them and answers.
GQL is the ISO standard graph query language (ISO/IEC 39075): you draw the pattern you are looking for, and Graphersal returns one row per match.
-- who created software together with marko?
MATCH (me:person {name: 'marko'})-[:created]->(s:software)<-[:created]-(other:person)
WHERE other <> me
RETURN other.name AS coworker, s.name AS software
ORDER BY coworker
Run it in the playground.
GQL reads and writes (INSERT, SET, REMOVE, DELETE), and familiar Cypher spellings such as
CREATE, MERGE, UNWIND or toUpper() are accepted as aliases where they mean the same, so a
query you already know usually runs as it is. GQL support is experimental and grows from release to
release: GQL Queries,
the supported subset.
Gremlin is the query language of Apache TinkerPop™: start somewhere in a graph, walk along its edges, filter, group and count.
// who created software together with marko?
g.v().has("name", "marko").as("me")
.out("created").in("created")
.where(P.neq("me"))
.path().by("name")
Run it in the playground:
the real engine, compiled to WebAssembly, runs in your browser. Nothing to install, and your data
never leaves your browser. Both languages run on the same graph and the same engine: a GQL query is
compiled into an ordinary traversal plan, with the same optimizer, indexes, profile(), limits and
permissions as Gremlin.
What you get
- GQL, the ISO standard. Pattern queries with
MATCH,OPTIONAL MATCH, aggregation, subqueries, quantified paths andUNION, and writes withINSERT,SET,REMOVE,DELETEandMERGE; Cypher spellings are accepted as aliases. Run a query withg.gql("MATCH ..."), in the playground's GQL tab, through MCP, or save it as a named query (experimental). - Gremlin, two ways. Build traversals in Rust or write them as text in the Gremlin DSL, in
snake_case or in Gremlin's own camelCase (
has_labelorhasLabel). The same text runs in the browser, on the command line, from Python and through an AI agent. - A playground in the browser. Write a query and see a table, the graph drawing, the schema and the optimized plan.
- A command line tool. One-shot queries for shell scripts, an interactive REPL with completion and help, and a local server that brings the playground UI to a graph on your disk.
- AI agents on your graph. The server speaks the Model Context Protocol (MCP), so Claude Code or another MCP client can query the graph you are looking at, in GQL or in Gremlin. In the playground's AI Chat tab you ask about your graph in plain language, and the model of your choice writes and runs the queries (experimental).
- Values with real types. Besides numbers, strings, UUIDs and nested JSON: five date and time
types modelled on PostgreSQL (time zones from the IANA database, calendar-correct arithmetic,
TinkerPop's date steps), and vectors for embeddings (
f32,f16,i8,bit) with exact similarity search (nearest(), cosine, dot, L2, Hamming) and quantization. A string that looks like a date stays a string: types come from a schema or a typed value, never from guessing. - Safe by construction. Every traversal is atomic: it commits completely or leaves nothing
behind. Schemas (a subset of JSON Schema) are enforced on write and fill create-time defaults
(
default,uuidv7,now). Limits, timeouts and permissions make it safe to run queries you did not write. - Durable when you need it. A graph lives in memory, and the Store keeps it on disk: every commit goes to a write-ahead log, and you can go back to any point in time, fork, roll back, back up and repair. The file format is a public specification.
- Fast and observable. A rule-based optimizer rewrites each query and answers
has()filters from declared property indexes (g.create_index(..));profile()shows the optimized plan with timings, traverser counts and memory per step. - Open for integration. Rust and Python APIs, saved (named, parameterized) queries stored in the graph, change capture with commit hooks, GraphSON 3.0 and GraphML files, and a storage trait to run the whole engine on a storage of your own.
Install
- Prebuilt binaries for Linux, macOS and Windows: the archives on the
releases page, or
cargo binstall graphersal-cli. - From source:
cargo install graphersal-cli(Rust 1.88 or newer); the binary isgraphersal. - Python:
pip install graphersal. Rust:cargo add graphersal --features script,io,display.
The Linux binaries are statically linked with musl and run on any distribution, but are slower on allocation-heavy queries than a source build. Checksums, WSL and the macOS/Windows prompts: Installation.
Get started
In the browser
Open play.graphersal.dev, pick a sample graph and press Run. The playground tour shows every panel.
On the command line
graphersal -e 'g.v().has("name", "marko").out("knows").values("name")'
graphersal -e 'g.gql("MATCH (p:person)-[:knows]->(f) RETURN f.name AS friend")' # GQL
graphersal --graph people.json -e 'g.v().has_label("person").count()' # GraphSON or GraphML
graphersal # interactive REPL
graphersal --graph people.json --server --mcp # the playground UI + MCP on http://127.0.0.1:8080
The result goes to stdout, a diagnostic to stderr, and a failing query exits with 1, so a shell
script or a CI job can check a graph. See The Command Line
and Dev Server, MCP and AI Chat.
From Rust
[dependencies]
graphersal = { version = "0.3", features = ["script", "io", "display", "gql"] }
use graphersal::prelude::*;
let graph = GraphSource::tinkerpop_modern();
let friends = graph
.read()
.traversal()
.v(None)
.has("name", "marko")
.out("knows")
.values("name")
.to_list()?; // ["josh", "vadas"]
// the same query as Gremlin text (feature `script`), and as GQL (features `script` and `gql`)
let graph = std::sync::Arc::new(graph);
let names = graphersal::script::eval_value(
graph.clone(),
r#"g.V().has("name", "marko").out("knows").values("name").toList()"#,
)?;
let rows = graphersal::script::eval_value(
graph,
r#"g.gql("MATCH (:person {name: 'marko'})-[:knows]->(f) RETURN f.name AS friend").toList()"#,
)?;
Every feature is off by default: script (the Gremlin DSL), gql (GQL queries), io (GraphSON
and GraphML), display (tables), serde, persist (snapshots, journal and the Store). See the
Rust Quick Start.
From Python
pip install graphersal
import graphersal
graph = graphersal.Graph.tinkerpop_modern()
graph.query('g.V().has("name", "marko").out("knows").values("name")')
# ['josh', 'vadas']
graph.query('''g.gql("MATCH (:person {name: 'marko'})-[:knows]->(f) RETURN f.name AS friend")''')
# [{'friend': 'josh'}, {'friend': 'vadas'}]
See the Python Quick Start.
How mature is it
Graphersal 0.3 is an early release line, built with the care of a database:
- TinkerPop conformance. Apache TinkerPop's own Gherkin test suite (3.8.2) runs on every test run. More than 97 % of the scenarios in scope pass, and no implemented step gives a wrong result. The rest are steps that are not implemented yet or differ on purpose; each difference is documented (compliance, deviations).
- GQL conformance. Which parts of ISO/IEC 39075 are supported is listed feature by feature (GQL conformance); how far the Cypher compatibility forms agree with Neo4j's behaviour is measured against the openCypher TCK on every test run (TCK compliance), and no supported construct gives a wrong result there. GQL is experimental: its subset grows, and an answer may still change.
- Tested hard. About 90 % line coverage; randomized differential tests and fuzzing of queries,
file decoders, checkpoints and backups run in every
cargo test, with long budgets before each release. A query that goes wrong ends in an error with ahelp()text, never in a crash. - A public storage format. Snapshots, the write-ahead log and the Store are described byte by byte in the format specification; every decoder treats its input as hostile.
- Clear stability labels. Within 0.3.x the public API of
graphersal(outside the items marked experimental), the DSL and the schema format change only additively. GQL, the storage traits (GraphStorage,PersistentStorage,StoreDir) and the AI Chat are experimental, and the dev server's HTTP API is internal.
Graphersal is not a complete copy of TinkerPop. Read Graphersal and TinkerPop for what is the same, what is different and why.
Repository
Building from source needs Rust 1.88 or newer:
cargo build --release -p graphersal-cli # target/release/graphersal
Contributing
Bug reports, questions and pull requests are welcome. Contributions are accepted under the Contributor License Agreement, signed once with a comment on your first pull request; see CONTRIBUTING.md. Please report security issues privately as described in SECURITY.md.
License
Licensed under the Apache License, Version 2.0; see also NOTICE. Use of the project name is described in TRADEMARKS.md.
Graphersal is compatible with, and inspired by, Apache TinkerPop Gremlin. It is an independent project: it is not part of Apache TinkerPop and is not endorsed by the Apache Software Foundation. Apache TinkerPop, TinkerPop and Gremlin are trademarks of the Apache Software Foundation.
Graphersal's GQL is measured against the openCypher TCK and accepts Cypher compatibility forms. It is not Cypher and not openCypher, and it is not affiliated with, endorsed by or sponsored by Neo4j or the openCypher Implementers Group. Cypher® is a registered trademark of Neo4j Inc.; the names Cypher and openCypher are used here only to describe compatibility testing.
