Skip to content

Repository files navigation

littlegraph

littlegraph is an embedded graph database written in Rust. It reads and writes Neo4j Record Storage Engine database files directly and provides graph queries and updates through openCypher.

The project is in an early stage of development. Its API, Cypher surface, and storage compatibility may change. Do not open a database directory while Neo4j is using it, and keep a backup before using writable mode.

Features

  • Uses Neo4j record storage directly, without a custom persistence format.
  • Provides explicit read-only and offline writable open modes.
  • Supports nodes, relationships, labels, relationship types, and properties.
  • Supports common openCypher queries and restricted CREATE, node MERGE, SET, REMOVE, and DELETE updates.
  • Supports a bounded set of Neo4j-compatible built-in CALL procedures.
  • Provides auto-commit transactions, explicit transactions, savepoints, timeouts, cancellation, and workspace limits.
  • Includes an embeddable Rust library, an interactive REPL, and a Cypher script loader.
  • Serves direct Bolt 5.4 connections for Neo4j-compatible drivers.

Quick Start

littlegraph requires a Rust 2021-compatible toolchain and Cargo. The first build must fetch the cypher-rs Git dependency.

Build the workspace from the repository root:

cargo build --workspace

Load the included user-friends example:

cargo run -p littlegraph -- load \
  tmp/friends \
  examples/user-friends/graph.cyp

When the target directory is missing or empty, the command initializes an aligned-1.1 Neo4j record store. Open the interactive console on the same store:

cargo run -p littlegraph -- repl tmp/friends

Enter a query in the REPL and terminate it with a semicolon:

MATCH (u:User)-[:FRIEND]->(friend:User)
RETURN u.name, friend.name
ORDER BY u.name, friend.name;

Use :exit, :quit, or EOF to leave the console.

Command Line

littlegraph repl <neo4j-database-dir>
littlegraph load <neo4j-database-dir> [<cypher-file|->]
littlegraph serve <neo4j-database-dir> [--bolt <host:port>] \
  [--bolt-auth-file <path>] \
  [--query <host:port>] [--query-bearer-token <token>]

serve requires at least one of --bolt or --query.

load reads the named script. When the file is omitted or is -, it reads standard input:

printf 'CREATE (:Person {name: "Alice"});' | \
  cargo run -p littlegraph -- load ./data/example -

load executes the entire script in one transaction. It commits only after every statement succeeds; otherwise it rolls back all changes and exits with a failure status. Scripts do not use :begin, :commit, or :rollback; those transaction commands are available only in the interactive console.

Bolt Server

Start a plaintext Bolt listener with:

cargo run -p littlegraph -- serve ./data/example --bolt 127.0.0.1:7687

Connect with a direct bolt:// URI, encryption disabled, and the driver's no-auth authentication token. The server implements Bolt 5.4, auto-commit and explicit transactions, result paging, reset-after-failure, and a single-server routing table. The default database name is neo4j.

Configure fixed Bolt usernames and passwords with --bolt-auth-file. It requires --bolt. The UTF-8 text file contains one user:password entry per line. Usernames and passwords must be non-empty, usernames must be unique, and blank lines are rejected. The first colon separates each username from its password, so passwords may contain additional colons:

printf '%s\n' 'app-user:local-secret' 'reader:another-secret' > auth.txt
chmod 600 auth.txt
cargo run -p littlegraph -- serve ./data/example \
  --bolt 127.0.0.1:7687 --bolt-auth-file auth.txt

Clients must use the driver's Basic authentication token when this option is set. The credentials are loaded at startup and are not persisted in the database. User management, roles, authorization, and credential rotation are not provided. Restrict access to the authentication file and use TLS when clients connect over an untrusted network.

Query API Server

Use --query to start Neo4j's HTTP Query API v2, either alone or beside Bolt:

cargo run -p littlegraph -- serve ./data/example \
  --query 127.0.0.1:7474

littlegraph exposes its single database as self. Execute an auto-commit query at POST /db/self/query/v2:

curl http://127.0.0.1:7474/db/self/query/v2 \
  -H 'Content-Type: application/json' \
  -d '{"statement":"RETURN 1"}'

The /tx, /tx/{id}, and /tx/{id}/commit endpoints support explicit transactions. Plain JSON, typed Query API JSON v1.0/v1.1, and their JSON Lines response formats are available for the value types supported by littlegraph.

Configure an HTTP bearer credential with --query-bearer-token. It requires --query and does not change Bolt authentication:

cargo run -p littlegraph -- serve ./data/example \
  --bolt 127.0.0.1:7687 --query 127.0.0.1:7474 \
  --query-bearer-token local-secret

To require TLS, provide a PEM bundle containing the server certificate chain and its unencrypted private key:

cat server.crt server.key > server.pem
cargo run -p littlegraph -- serve ./data/example \
  --bolt 127.0.0.1:7687 --tls-cert server.pem

For a certificate issued by a private CA, add the CA certificate to the chain:

cargo run -p littlegraph -- serve ./data/example \
  --bolt 127.0.0.1:7687 --tls-cert server.pem --tls-ca root-ca.pem

TLS is required whenever --tls-cert is present; every configured Bolt and Query API listener uses the same certificate and does not also accept plaintext. --tls-ca sends the private CA certificate as part of the server chain and does not enable client-certificate authentication. Clients must still trust that CA (or accept a self-signed certificate).

Bolt bearer authentication, user management, authorization, WebSocket transport, other Bolt versions, causal bookmarks, and clustering are not supported. Query parameters support null, booleans, signed integers, floats, strings, lists, and maps. Results additionally support nodes, relationships, and paths. Temporal, spatial, byte-array, and vector values are not currently supported.

Pinned JavaScript, Java, and Python official-driver smoke suites and their running instructions are available in interop/README.md.

Rust API

The littlegraph-core crate exposes the embedded API. Open an existing Neo4j database in read-only mode:

use littlegraph_core::{Graph, Params};

fn main() -> littlegraph_core::Result<()> {
    let mut graph = Graph::open_neo4j("/path/to/neo4j/data/databases/example")?;
    let result = graph.query(
        "MATCH (n:Person) RETURN n.name ORDER BY n.name",
        Params::new(),
    )?;

    println!("columns: {:?}", result.columns);
    for row in result.rows {
        println!("{:?}", row.values);
    }
    Ok(())
}

Use Graph::open_neo4j_writable when updates are required. Multiple operations can be grouped in one transaction:

use littlegraph_core::{Graph, Params};

fn add_people(mut graph: Graph) -> littlegraph_core::Result<()> {
    let mut tx = graph.transaction()?;
    tx.query("CREATE (:Person {name: 'Alice'})", Params::new())?;
    tx.query("CREATE (:Person {name: 'Bob'})", Params::new())?;
tx.commit()
}

Graph::run_transaction(max_retries, closure) and Graph::run_transaction_with_options(options, max_retries, closure) can replay a deterministic transaction closure automatically when its snapshot conflicts with another writer. The closure must not perform external side effects because it may run more than once.

Dropping an uncommitted Transaction rolls it back. Transactions also provide savepoint, rollback_to, and release_savepoint. TransactionOptions adds timeouts, cancellation, spill controls, and deterministic workspace limits.

Storage Compatibility

littlegraph supports only the Neo4j Record Storage Engine formats:

  • standard-1.1
  • aligned-1.1

Read-only mode requires a normally closed database and never performs recovery. Writable mode is offline-only. Writable graphs in one process share an MVCC coordinator and the Neo4j database lock; transactions use stable snapshots, validate fixed-record before images, and can rebase disjoint record patches, including in-place dynamic string and array chains and updates first staged after a transaction becomes stale. Counts deltas and pure ID reclamation are merged from the latest committed roots after entity records validate, including for disjoint sparse relationship deletions. Relationship group degree deltas also merge after their fixed records validate. High-water allocation and dynamic chain resize may rebase when their physical records are disjoint. ID reuse may rebase when free-list selection is unchanged, and token changes follow the same record and selection validation. The store must have a valid shutdown checkpoint with no active schema indexes or constraints. The writer also has restrictions around property encoding, dynamic record reclamation, and some graph updates.

See docs/neo4j-storage.md for the complete storage rules and limitations.

openCypher Support

The current query interface covers common uses of:

  • MATCH, OPTIONAL MATCH, WHERE, and WITH
  • RETURN, aliases, DISTINCT, aggregation, and common functions
  • ORDER BY, SKIP, and LIMIT
  • node and relationship patterns, literals, lists, maps, and parameters
  • UNWIND
  • restricted CREATE, node MERGE, SET, REMOVE, and DELETE

This is not a complete openCypher implementation. Syntax accepted by the parser may still be rejected by the executor or the offline Neo4j writer. The public query path currently does not support features such as UNION, CALL subqueries, FOREACH, relationship MERGE, and variable-length relationships. See the current syntax notes and known gaps:

Repository Layout

crates/core/              Query, transaction, and Neo4j storage implementation
crates/bolt/              Bolt 5.4 protocol and server implementation
crates/littlegraph/       REPL, script loader, and server CLI
examples/                 Runnable examples
docs/                     Storage design, compatibility, and feature notes
tools/                    Neo4j fixture utilities
vendors/neo4j/            Neo4j source used as an implementation reference

Development

cargo fmt --all -- --check
cargo test --workspace

Neo4j interoperability tests live in crates/core/tests/. Some tests require external Neo4j fixtures or tools; see tools/neo4j-fixture-generator/README.md for setup details.

About

an embeded graph database which speeks openCypher

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages