TerminusDB vs Neo4j

Open inAnthropic

A factual comparison of TerminusDB and Neo4j for developers evaluating graph databases. Both are graph databases, but they serve different use cases with fundamentally different architectures.

Executive summary

Neo4j is a property graph database optimised for real-time graph traversal at scale — social networks, recommendation engines, fraud detection. It uses the Cypher query language and stores data as labeled nodes with typed relationships.

TerminusDB is a document graph database with built-in version control — it stores JSON documents in a schema-enforced graph, tracks every change as an immutable commit, and supports branch, diff, merge, and time-travel. It uses the WOQL datalog engine for queries.

The key architectural difference: Neo4j is a mutable database designed for high-throughput real-time queries. TerminusDB is an immutable database designed for collaborative data workflows with full audit history.


Comparison table

AspectTerminusDBNeo4j
Data modelJSON documents decomposed into RDF triplesProperty graph (nodes + relationships + properties)
SchemaEnforced on every transaction (closed-world)Optional constraints (open-world by default)
Query languageWOQL (Datalog with unification)Cypher (declarative pattern matching)
Version controlBuilt-in: branch, merge, diff, time-travelNot built-in (requires external tooling)
ImmutabilityAppend-only delta layers, never mutatesMutable in-place updates
ACID transactionsFull ACID with snapshot isolationFull ACID
CollaborationClone, push, pull between instancesClustering for HA, no data-level collaboration
Scalability modelSingle-node with delta compressionClustering (Enterprise), sharding (Aura)
DeploymentDocker container, ~120 MBJVM-based, requires Java runtime
LicenceApache 2.0GPL (Community) / Commercial (Enterprise)
Primary interfaceHTTP REST API + client librariesBolt protocol + HTTP + client drivers
Graph traversalWOQL path() expressionsCypher variable-length patterns
Audit trailEvery commit has author, message, timestampRequires custom implementation
Schema migrationSchema weakening (backward-compatible only)Manual migration scripts

Data model

Neo4j: property graph

Neo4j stores data as nodes (entities) connected by relationships (edges). Both nodes and relationships carry properties (key-value pairs) and labels (type tags).

Example: cypher
CREATE (p:Person {name: "Alice", age: 30})
CREATE (c:City {name: "London"})
CREATE (p)-[:LIVES_IN {since: 2020}]->(c)

The property graph model is intuitive for developers coming from object-oriented backgrounds — entities feel like objects, relationships feel like pointers.

TerminusDB: document graph

TerminusDB stores data as JSON documents that are decomposed into a typed graph of triples. The schema defines document types and their relationships:

Example: JSON
{"@type": "Person", "name": "Alice", "age": 30, "lives_in": "City/London"}

Under the hood, this becomes RDF triples that can be traversed with WOQL. You interact with JSON documents; the graph is the engine:

Example: JavaScript
WOQL.and(
  WOQL.triple("v:Person", "rdf:type", "@schema:Person"),
  WOQL.triple("v:Person", "name", "v:Name"),
  WOQL.triple("v:Person", "lives_in", "v:City"),
  WOQL.triple("v:City", "name", "v:CityName")
)

Query language

Cypher (Neo4j)

Cypher uses ASCII-art patterns that visually resemble the graph structure:

Example: cypher
MATCH (p:Person)-[:LIVES_IN]->(c:City)
WHERE c.name = "London"
RETURN p.name, p.age

Cypher excels at expressing graph patterns intuitively. Variable-length path matching (*1..5) handles recursive traversal concisely.

WOQL (TerminusDB)

WOQL uses Datalog-style pattern matching with unification:

Example: JavaScript
WOQL.and(
  WOQL.triple("v:Person", "lives_in", "v:City"),
  WOQL.triple("v:City", "name", WOQL.string("London")),
  WOQL.triple("v:Person", "name", "v:Name"),
  WOQL.triple("v:Person", "age", "v:Age")
)

WOQL's strength is composability — queries are programs that can be nested, abstracted, and combined. The path() operator handles recursive traversal.


Version control

This is where the databases diverge most significantly.

TerminusDB: git for data

Every write in TerminusDB creates an immutable commit. You can:

  • Branch — create isolated workspaces for changes
  • Diff — compare any two states at the field level
  • Merge — apply changes from one branch to another
  • Time-travel — query the database at any historical commit
  • Clone — replicate databases between instances

This enables collaborative data workflows: multiple teams work on branches, review changes via diff, and merge when ready — exactly like Git for code.

Neo4j: no built-in version control

Neo4j mutates data in place. To achieve version control, you would need to:

  • Build a custom changelog system
  • Use external tools (e.g., Liquigraph for schema changes)
  • Implement your own branch/merge logic at the application layer

For use cases that need audit trails or collaborative editing, this is significant additional engineering work.


Schema enforcement

TerminusDB: closed-world assumption

TerminusDB enforces schema on every transaction. You cannot insert a document that violates its class definition. This provides strong guarantees:

  • Every document conforms to its type
  • Relationships are typed and validated
  • Schema changes follow the weakening principle (backward-compatible only)

Neo4j: open-world by default

Neo4j is schema-optional. You can add constraints (uniqueness, existence, node key) but the graph is open-world by default — any node can have any property, any label combination.

Neo4j 5+ added type constraints and property type constraints, but enforcement is opt-in rather than default.


When to choose Neo4j

  • Real-time recommendation engines — Neo4j's query planner is optimised for low-latency traversal at scale
  • Social network analysis — finding shortest paths, community detection, influence scoring
  • Fraud detection — pattern matching across transaction networks in real time
  • Large-scale graph analytics — when you need graph algorithms (PageRank, betweenness centrality)
  • Existing Cypher expertise — large ecosystem of tools, connectors, and community resources
  • Clustering requirements — Neo4j Enterprise provides multi-node clusters for HA

When to choose TerminusDB

  • Collaborative data workflows — teams editing shared datasets with branch/merge workflows
  • Regulated industries — finance, healthcare, compliance where full audit trail is mandatory
  • Schema-first development — when you want the database to enforce data integrity, not the application
  • Content versioning — knowledge bases, documentation, reference data that evolve over time
  • Data lineage and compliance — proving what changed, when, and by whom
  • Lightweight deployment — single Docker container, no JVM, minimal infrastructure
  • Distributed data collaboration — clone and sync between instances (edge computing, partner data sharing)

Worked example: tracking product changes

Suppose you need to track product catalogue changes with full history and review workflow.

In Neo4j

You would need to model versioning explicitly:

Example: cypher
CREATE (p:Product {id: "widget-1", name: "Widget", price: 9.99, version: 1})
CREATE (p)-[:SUPERSEDED_BY]->(:Product {id: "widget-1", name: "Widget Pro", price: 14.99, version: 2})

History, diff, and rollback become application-level concerns.

In TerminusDB

Version control is built in:

# Create a branch for the price change
curl -X POST http://localhost:6363/api/branch/admin/catalogue/local/branch/price-update \
  -d '{"origin": "admin/catalogue/local/branch/main"}'

# Update the product on the branch
curl -X PUT "http://localhost:6363/api/document/admin/catalogue/local/branch/price-update?author=alice&message=Update+widget+price" \
  -d '{"@id": "Product/widget-1", "@type": "Product", "name": "Widget Pro", "price": 14.99}'

# See exactly what changed
curl -X POST http://localhost:6363/api/diff/admin/catalogue \
  -d '{"before_data_version": "main", "after_data_version": "price-update"}'

# Merge when approved
curl -X POST http://localhost:6363/api/apply/admin/catalogue/local/branch/main \
  -d '{"before_commit": "main", "after_commit": "price-update", "commit_info": {"author": "alice", "message": "Merge price update"}}'

The full history is preserved. You can time-travel to see the product at any point. Diff shows exactly what changed. No application-level versioning code required.


Summary

Neo4j and TerminusDB are both graph databases, but optimised for different problems:

  • Neo4j excels at real-time graph traversal, analytics, and pattern matching at scale
  • TerminusDB excels at collaborative, auditable data workflows with built-in version control

They are not direct substitutes — they serve different architectural needs. Choose based on whether your primary challenge is querying complex relationships in real time (Neo4j) or managing evolving data with history and collaboration (TerminusDB).

Was this helpful?