TypeDB vs Neo4j

Graph modelling for domains that have to be right

Neo4j is a fast, flexible property graph. TypeDB is a typed graph database that models complex domains and catches mistakes as they happen. Here's how to tell which one your project needs.

Get TypeDB open source
TypeDB
  1. 1
  2. 2
  3. 3
  4. 4
match
  $b isa company, has name "Acme Ltd";
  $l isa loan, links (borrower: $b, guaranter: $g);
fetch { "guarantor": $g.name };
Error: type check failed
Role loan:guaranter is not defined. Did you mean loan:guarantor?
Neo4j
  1. 1
  2. 2
  3. 3
MATCH (b:Company {name: "Acme Ltd"})
  <-[:BORROWER]-(l:Loan)-[:GUARANTER]->(g)
RETURN g.name;
0 rows returned

Overview

Main differences from Neo4j

We typically see businesses choose TypeDB when they have large, messy domains, when they are dealing with critical systems that require accuracy, or when they want their data architecture to give them an unfair AI advantage.

Relationships with more than two sides

Neo4j edges join two nodes. TypeDB relations take any number of participants, each in a named role.

Mistakes you can see

Neo4j accepts most writes and runs most queries by default. TypeDB checks both against your schema.

A model that grows with you

TypeDB subtypes inherit from their parents, and queries pick them up. Reshaping a Neo4j relationship means migrating data.

Relationships

Two sides, or as many as it takes

Real relationships often involve more than two things. A purchase has a buyer, a seller, a product and a broker.

Modelling those participants directly, instead of routing them through intermediate nodes, reduces bloat in the data itself: one enterprise project reported 3x fewer facts stored for the same data in TypeDB vs. in Neo4j!

TypeDB

One relation connects all four, each in a named role. Relations can own attributes and play roles in other relations, so an ownership can itself be disputed.

Neo4j

Each edge joins two nodes, so the purchase becomes an intermediate node. What each participant's role means is a convention your queries have to follow.

Types

Labels, or a type hierarchy

Most enterprise domains have categories within categories. Two things matter: subtyping, where a query on a parent returns its children, and inheritance, where what you add to a parent applies to its children.

TypeDB
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
entity company, owns location;
entity public-company, sub company;
entity private-company, sub company;

match $c isa company;

Subtyping: ask for every company and get both subtypes, plus any added later.

Inheritance: add location to company and every subtype owns it. Both work for relations and attributes too.

Neo4j
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
MATCH (c)
WHERE c:Company OR c:PublicCompany
   OR c:PrivateCompany
RETURN c;

Subtyping: emulated by giving nodes several labels, so every write has to add both. Enterprise Edition can require one label to imply another. Each relationship has exactly one type, so relationships have no subtypes.

Inheritance: none. Properties aren't declared on types; a constraint on a shared label is the closest equivalent.

Functions

Logic in the schema, or in a plugin

Both let you define your own functions. Where they live, and who can change them, is very different.

TypeDB
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
fun exposure($c: company) -> decimal:
  match $l isa loan,
    links (guarantor: $c), has amount $a;
  return sum($a);

Functions are written in TypeQL, stored in the schema and called from any query. They're type-checked against the model, and can be recursive.

Neo4j

User-defined functions are written in Java, packaged as a JAR and deployed to the server's plugins folder, then the server is restarted. They sit outside the schema, and custom code can't be deployed on AuraDB.

Catching mistakes

Where errors show up

TypeDB checks at three points: when you change the schema, when you commit data, and when you write a query. Neo4j is permissive by default.

TypeDBNeo4j
Write with a misspelt label Rejected: the type isn't defined Accepted, and a new label is created
Relationship between the wrong kinds of thing Rejected: that type can't play that role Accepted, unless a constraint or graph type covers it
Query with a misspelt relationship type Fails with an error naming the problem Runs, returns no rows, raises a warning
Query for something impossible, like a person's engine size Fails: a person can't have an engine size Runs and returns nothing

Neo4j constraints and graph types are opt-in, and graph types are open, so data they don't describe can still be written. A broken query that returns nothing looks exactly like a correct one.

93%of incorrect TypeQL queries came back as an error you could act on
40%of incorrect Cypher queries did the same; the rest failed silently

First-attempt queries written by Claude Sonnet 5 over the same dataset, counting only the incorrect queries. See the full benchmark →

Extending the model

When the model needs to change

Say you've stored employment as an edge between a person and a company, and now you need to record the department too.

TypeDB

Add a department role to the employment relation. Existing data and queries keep working. Renaming types or restructuring a hierarchy still needs a migration.

Neo4j

Adding labels and properties is instant. A third participant means turning the EMPLOYED_BY edge into a node, migrating the data and rewriting the queries that used it.

Performance

Faster small, steadier large

We ran TPC-C on both, growing the dataset until it no longer fitted in memory.

+75%more work completed by TypeDB at 400 warehouses (about 100 GB), once data outgrew memory
< 200 msTypeDB's slowest transaction at that size. Neo4j's reached several seconds, though it was faster on two of five workloads.
2.5xNeo4j's throughput advantage on the smallest dataset, while everything fits in memory

TPC-C, TypeDB CE 3.4.1 vs Neo4j CE 5.26.5, single-threaded, 8 cores, 16 GB RAM. Read the write-up →

Use Cases

What teams build on TypeDB

01 · Agent grounding

Give agents a model of your domain they can check their work against.

  • Agents query the same typed model your application uses
  • Wrong queries come back as errors the agent can fix
  • Connect through MCP and a TypeDB skill
match
  $c isa customer, has name "Acme";
  $p isa policy, links (holder: $c);
fetch { "policy": $p.ref };

Which to choose

Pick the one that fits the problem

Choose TypeDB when

  • your domain has many interdependent types and will keep growing
  • relationships involve more than two parties, or need nesting
  • you work in a regulated domain where the data's shape mustn't drift
  • you want the database to reject invalid data and queries
  • agents will be writing queries against your data

Choose Neo4j when

  • your workload is traversal, pathfinding or graph analytics
  • your model is simple and unlikely to grow much more complex
  • you need to load data before the schema is agreed
  • your team knows Cypher, or wants the established ecosystem and tooling

Reference

The full comparison

TypeDBNeo4j
Data model Entities, relations and attributes, all typed Nodes, relationships and properties
Schema Required and enforced; can start small and grow Optional; constraints and graph types as needed
Relationships Any number of participants in named roles; can nest Directed edges between two nodes
Subtyping Native for entities, relations and attributes Emulated with multiple labels; none for relationships
Inheritance Attributes and roles inherited from parent types None; constraints on a shared label are the closest equivalent
Bad writes Rejected if they don't fit the model Accepted unless a constraint or graph type covers them
Bad queries Type-checked first; mistakes return errors Run; unknown names return no rows and a warning
Path queries Recursive functions; more code for open-ended paths Concise variable-length paths
Functions Written in TypeQL, stored in the schema Written in Java, deployed as server plugins
Graph analytics Through external tools Built in
Larger-than-memory data Throughput holds up better as data grows Fastest while data fits in memory
Ecosystem Smaller and growing Large and established

Move from Neo4j.
Keep the graph. Gain a model that checks itself.

Get TypeDB open sourceTalk to us
Feedback