Two weeks ago I was drafting a recommendation table for a code knowledge graph MCP: SQLite up to about 100k nodes, Kuzu from 100k to a million, Neo4j past that. It was a clean answer. I ran the numbers, I trusted the ladder, I moved on.
Then a colleague pointed me at a Register piece from October 14, 2025. Kuzu's GitHub repo had been archived. Apple had bought Kùzu Inc. on October 9, and the 9to5Mac follow-up in February 2026 traced it to an EU Digital Markets Act filing (The Register: KuzuDB abandoned, 9to5Mac: Kuzu joins Apple's list). The final release, 0.11.3, shipped the same day the repo went dark.
That changed the middle rung of the ladder. This post is the re-selection I actually shipped, at the four scales you might have: 10k, 100k, 1M, and past 1M code nodes. FalkorDB gets a section too because its GraphBLAS engine is genuinely fast in one specific lane, and pretending otherwise would be dishonest.
First: sizing your codebase in nodes, not lines
Before you pick a graph DB, translate your repo into node count. For a minimal schema of File / Module / Class / Function / Variable plus six edge types, this is the shape I keep seeing:
| Lines of code | Nodes | Edges |
|---|---|---|
| 10,000 | ~3,000 | ~8,000 |
| 100,000 | ~30,000 | ~80,000 |
| 300,000 | ~100,000 | ~270,000 |
| 1,000,000 | ~300,000 | ~800,000 |
The node-to-edge ratio hovers around 1:2.5 because an average function calls two or three others. Semantic edges (added later, if you build a Pass 2) push it higher, but the table above is the baseline. A 1M-node code graph means about 3M lines of source, which is Google or Meta scale monorepo territory. Most teams live in the 30k-300k node band.
Under 100k nodes: SQLite, and the one index that decides everything
For anything under 100k nodes I still recommend SQLite. Three reasons hold up:
-
Zero infrastructure. Ship a
.codegraph.dbfile inside the repo.git cloneand the tool works. No Docker, no auth, nodocker-composefile that no one wants to review. - Recursive CTE handles 3-5 hop BFS. For a hop-3 blast radius query on a 100k-node graph, SQLite returns in 50-150ms in my measurements. Good enough to sit behind an MCP tool.
- You already have the driver. Every language you might build an MCP in already has SQLite bindings in the standard library.
The catch is one index: edges(dst, type). Without it, reverse traversals (who calls this function?) fall off a cliff, because SQLite has to scan every edge row. With it, they stay in tens of milliseconds. If you take one thing from this post, take this: on SQLite, edges(dst, type) is not optional. I have seen four independent code-KG implementations, and every one of them either had this index or was silently unusable.
OSS reference points: code-review-graph and CodeGraph both run on SQLite with FTS5 for symbol lookup.
100k-1M nodes: Kuzu was the answer, and it still is (with an asterisk)
This is the band that changed. Until October 2025 the answer was Kuzu, and honestly it still is on the merits. Kuzu was embedded like SQLite (no server), spoke Cypher, and shipped with real graph indices instead of asking you to bolt them onto B-trees. On the 300k-node codebases I profiled, hop-3 traversals dropped from SQLite's 800ms into Kuzu's 40-80ms range.
The asterisk is that the repo is archived, the maintainers moved to Apple, and there is no roadmap. What you get today:
- LadybugDB, a community fork under a permissive license, keeps Kuzu's columnar storage, Cypher dialect, and the last vector and full-text indices intact (ArcadeDB's Neo4j alternatives writeup, 2026). If you already know Kuzu, LadybugDB is a straight lift.
- Bighorn, another fork by Kineviz, exists but has less traction.
- Kuzu 0.11.3 itself still works. It is not going to acquire security bugs because you stopped writing to it. For an internal code KG behind an MCP tool, an abandoned but functional DB is usable; for a customer-facing service, it is a policy decision.
Would I start a new project on LadybugDB today? For the 100k-1M code node band, yes, provided the team is comfortable with a small-community fork. If that word "fork" makes your legal team nervous, skip to Neo4j.
Past 1M nodes: Neo4j, and the boring reason it wins here
Once you cross a million nodes you are also past the point where "embedded" is a virtue. You have multiple engineers hitting the same graph, you want a query log, you want backup tooling that already exists. That is server-shaped work, and Neo4j is the mature server-shaped answer.
Cypher travels from Kuzu / LadybugDB to Neo4j with only dialect nicks, so if the codebase grows out of Kuzu you migrate rather than rewrite. Neo4j Community handles most single-node code-KG workloads; you reach for Enterprise (or Aura) when you need clustering.
The scale ceiling story worth knowing: NTT Comware runs Neo4j on a ~40M-node network device management graph in production, with query times dropping from about 80 minutes to tens of seconds after the migration (Neo4j case: NTT Comware). That is not a code KG, it is network topology, but it establishes the upper bound. If you are worried about Neo4j surviving your monorepo, it will.
Where FalkorDB actually belongs
FalkorDB is easy to mis-place because its benchmark numbers are impressive in isolation. FalkorDB reports sub-140ms p99 on aggregate expansion patterns where Neo4j hits 46.9 seconds (FalkorDB benchmark writeup). It represents the graph as sparse adjacency matrices and executes traversals as GraphBLAS matrix operations, which is a very different physical model from Neo4j's B-tree pointer walks.
The caveats are equally real: FalkorDB's benchmark methodology is FalkorDB's own, tuning effort likely differs, and the workloads picked are the ones where sparse-matrix execution shines. In LDBC SNB results both vendors have wins.
Practical read: FalkorDB is a fit when you need very low read latency, your graph fits in memory, and you can tolerate reload time on restart. Real-time IDE integrations, live code-navigation panels, hot-path autocomplete. For a nightly code-KG rebuild that a code review MCP queries a few dozen times per PR, it is overkill. CodeGraphContext uses FalkorDB Lite as one option for exactly this "hot, small, ephemeral" pattern.
The selection matrix I actually use now
| Scale | First pick | Fallback | Not this |
|---|---|---|---|
| Under 100k | SQLite | LadybugDB (Kuzu fork) | Neo4j (operational overkill) |
| 100k - 1M | LadybugDB (with fork risk noted) | SQLite (up to ~200k), Neo4j (up to 1M) | Vanilla Kuzu 0.11.3 for customer-facing work |
| 1M - 10M | Neo4j | FalkorDB (if read-only and in-memory OK) | Anything embedded |
| Past 10M | Neo4j Cluster | -- | Embedded, period |
"Not this" is not a technical impossibility. You can run SQLite at 500k nodes; it just tips into "please stop" territory on hop-4 CTEs.
What I picked, and the migration escape hatch
For the specific project that started this — a code review MCP over a ~300k-node Python monorepo — I picked SQLite. The number was inside its comfort band, the repo was fine, and the team did not need a fork discussion at the review meeting. If it grows past 500k I will move to LadybugDB, and if the org grows past a million nodes we will migrate to Neo4j.
The escape hatch is the schema. If you keep the schema to a minimal common denominator (five node types, six edge types, confidence and line_range as plain properties), then the migration between any two of these four DBs is a CSV export and a LOAD CSV on the other side. The temptation is to reach for DB-specific features (Neo4j label hierarchies, Kuzu's custom indices, FalkorDB's matrix-native aggregates). Every one of those pins you.
Apple's move on Kuzu made one thing concrete: "the best embedded graph DB" is one board meeting away from being someone else's IP roadmap. Keep the schema portable. Pick the DB that fits your current scale. Move when the numbers, not the vendor's Twitter, tell you to.
If you are building a code knowledge graph and want the full schema, ingest pipeline, and MCP wiring in one place, I wrote it up in Knowledge Graph Practical Guide. It covers the Pass 1 / Pass 2 split, the edges(dst, type) gotcha in more detail, and the migration paths between the four DBs above.

Top comments (0)