Orchestrata Ultimate › Plans › research-oss-graph-alternatives-2026-07-06
Open-source Neo4j alternatives — research (2026-07-06)
Source: plans/research-oss-graph-alternatives-2026-07-06.md at 8a2cb42ad · last changed 2026-07-27 · first committed 2026-07-06 · 225 lines.
Prose pending.
Plan text
Open-source Neo4j alternatives — research (2026-07-06)
Question (user): what genuinely open-source alternatives to Neo4j exist, and should Orchestrata adopt one? "Open source" = OSI-approved license only; source-available (BSL/SSPL/Elastic/FSL) is disqualifying.
Adopter profile: Python 3.14, official neo4j driver over Bolt, self-hosted incus
containers, no cloud. Cypher: MERGE-heavy small transactions from parallel writers,
Neo4j-5 constraint DDL (FOR ... REQUIRE ... IS UNIQUE), datetime() temporals with
ORDER BY, label+property indexes, some full-text. The graph is the system of record
(~250K nodes, growing). Needs one durable production instance + a fleet of 3–6
disposable test instances where RAM-per-instance and startup seconds matter
(worker-parallel test suite, <5-min wall-clock goal).
Evaluation bar (sharpened by the TestRun incident and Memgraph findings):
- License: OSI-approved, verified against the LICENSE file, governance noted.
- Drop-in-ness: does the official
neo4jBolt driver work? Constraint DDL dialect? - Semantics, not just syntax: MERGE behavior under concurrent writers (lock-based vs optimistic+retry), ORDER BY null placement (nulls-first-on-DESC just caused a real bug here), temporal type fidelity.
- Durability: per-commit fsync? WAL+snapshot model? (Memgraph's default fsync every 100K tx is the cautionary example.)
- Fleet economics: idle RSS, cold-start seconds, container story.
- What it buys over Neo4j CE's GPLv3 gates: CE has NO replication, offline-only backup, no multi-database, no RBAC.
Survey — genuinely open-source candidates
Two structural findings (landscape agent, all licenses verified against LICENSE files, July 2026):
- There is NO genuinely open-source, production-grade, Bolt-compatible Neo4j alternative. Bolt speakers: Neo4j itself (GPLv3), Memgraph (BSL — disqualified), TuGraph-DB (partial Bolt, Apache-2.0, thin community/cadence), ONgDB (AGPLv3 fork frozen at Neo4j-4.3-era parity, dormant). "Keep the driver, swap the server" is not on the table.
- The licensing landscape churned hard 2024–2026: ArangoDB → BUSL (3.12); Kùzu abandoned Oct 2025 (sponsor acqui-hired), revived as MIT LadybugDB; Dgraph fully Apache-2.0 in v25; HugeGraph became an ASF top-level project (2026-02); FalkorDB turns out to be SSPL (not OSS, despite marketing); RedisGraph EOL'd 2025-01. Re-verify licenses at adoption time, always.
| Engine | License (verified) | Query lang | Bolt? | Fleet economics | Verdict |
|---|---|---|---|---|---|
| Neo4j CE 5.26 LTS | GPL-3.0 | Cypher (reference) | native | ~512MB–1GB JVM, 10–30s start | Incumbent; ALL our features are in CE; LTS to 2028-06 |
| Apache AGE | Apache-2.0 (ASF) | openCypher subset in SQL | no (PG wire) | ~50–100MB, <1s — best server fleet story | Best license/governance; port not a swap: no temporals in Cypher layer, no constraints, agtype parsing |
| LadybugDB (Kùzu fork) | MIT | Cypher dialect, schema-first | no (embedded) | megabytes, in-process, DB=directory | Closest dialect + unbeatable test-fleet mechanics; 9-month-old fork, format stability unproven |
| ArcadeDB (OrientDB successor) | Apache-2.0 | native openCypher-25 + SQL/Gremlin | no (PG wire, {cypher} prefix) |
few-hundred-MB JVM, seconds | Un-gates what Neo4j gates (multi-DB + HA free); young Cypher engine, small vendor |
| Dgraph v25 | Apache-2.0 | DQL/GraphQL — no Cypher | no | moderate Go | Wrong direction: full query rewrite |
| NebulaGraph | Apache-2.0 | nGQL (no MERGE, no constraints, no transactions) | no | 3 daemons, multi-GB | OSS core de-facto terminal (last release 2024-05; vendor on proprietary v5) |
| JanusGraph | Apache-2.0 (LF) | Gremlin | no | JVM + Cassandra/Scylla stack | Heavy + rewrite; poor fit |
| Apache HugeGraph | Apache-2.0 (ASF TLP 2026-02) | Gremlin-first, 2nd-class openCypher | no | ~1GB JVM | Healthy project, weak fit; RCE history (CVE-2024-27348) |
| TypeDB | MPL-2.0 | TypeQL (paradigm shift) | no | Rust, moderate | Out of scope for Cypher-first |
| OrientDB | Apache-2.0 | SQL/Gremlin | no | JVM | Maintenance mode; take ArcadeDB instead |
| TuGraph-DB | Apache-2.0 | openCypher + ISO GQL | partial | moderate C++ | Only Apache+Bolt engine; China-centric, cadence cooling (last release 2025-03) |
| AgensGraph | Apache-2.0 + PG | Cypher-in-SQL (PG fork) | no | PG-like | AGE is the same idea, better architecture/governance |
Disqualified (source-available, verified): Memgraph (BSL 1.1 — Appendix A), FalkorDB (SSPLv1 per its own license page; GitHub shows NOASSERTION), ArangoDB ≥3.12 (BUSL-1.1 + 100GiB non-commercial community binary), SurrealDB (BSL 1.1), RedisGraph (EOL 2025-01; successor is FalkorDB, SSPL).
ISO GQL (39075:2024) convergence: Cypher-derived; Neo4j Cypher 25 (2025.06+) aligns grammar with GQL and openCypher has redefined itself as "paving the road to GQL" — so Cypher-shaped code is the portability hedge, and staying on Neo4j CE does not strand us. TuGraph ships actual GQL; SQL/PGQ (DuckPGQ, MIT) is the relational adjacent.
Deep-dive — Apache AGE / Kùzu(LadybugDB) / FalkorDB / NebulaGraph
Five-agent web research, kill-critical claims verified against primary sources (license files, GitHub APIs, official docs). Full agent report in the session transcript; the decisive facts:
Apache AGE (Apache-2.0, ASF TLP — the right license and governance):
MERGE ... ON CREATE/ON MATCH SETis a SYNTAX ERROR in every released version through 1.7.0 (fix merged to master 2026-04, unreleased).- NO constraint DDL of any kind (unique-constraint request open since 2021); uniqueness = hand-written PG expression indexes on internal label tables.
- NO temporal types/functions;
datetime()request closed "not planned". - Cypher params only via SQL PREPARE/EXECUTE; no CALL {}; one label per node; official Python wrapper 3 years stale (psycopg + agtype parsing DIY).
- Its own dev list, 2025-05: "AGE doesn't support concurrent merge operation" (implicit-DDL races, duplicate nodes under READ COMMITTED); 10K-edge UNWIND+MERGE measured at 22 minutes.
- Genuinely excellent: PG WAL/MVCC durability, ~180MB image/<1s start, many-graphs-per-DB, Azure ships it first-party. Health: 20-month release gap, zero commits 2024-09..2025-05, recovered 2025-09+.
Kùzu → LadybugDB (MIT): Kùzu Inc. archived everything 2025-10-10 — the
team was acqui-hired by APPLE (EU filing surfaced 2026-02). LadybugDB is the
leading fork (~monthly releases). One RW process per database (file lock),
single effective writer within it — the Vela fork exists specifically to add
multi-writer. ORDER BY defaults NULLS FIRST ascending (opposite of Neo4j).
No datetime(), no CALL {}, PK-only uniqueness, DDL-first schema. Frozen
corruption-bug ledger from 0.11.3. Our first-party spike (above) measured the
rest. Graphiti deprecated its Kuzu backend; GitLab is migrating off.
FalkorDB: SSPLv1 per its own README/LICENSE — source-available, disqualified. Its Bolt support is marked "experimental, not for production" by its own docs. Re-evaluate only if it relicenses.
NebulaGraph OSS (Apache-2.0, single vendor + CLA): last OSS release v3.8.0 2024-05-17 — 26 months, 3 master commits in 18 months, nightlies stopped; vendor ships proprietary v5.x. nGQL: NO MERGE (official FAQ), no constraints (VID-only identity), NO transactions, no CALL; docs verbatim: "Don't use UPSERT for scenarios with highly concurrent writes" — our exact workload. 3-daemon topology, 8GB test minimum, ~20s async DDL. Out on every axis.
Neo4j CE baseline precision (verified): GPLv3; exactly ONE user database; property-UNIQUENESS constraints only (existence/type/key = Enterprise); no RBAC (all users implied admins); offline dump only; 5.26 LTS supported to 2028-06-06 (next LTS ~2026-11). Everything Orchestrata uses today is in CE. The only OSI-licensed Bolt speaker in 2026 is ArcadeDB (Apache-2.0, Bolt 3.0/4.0/4.4 plugin, vendor-claimed 97.8% openCypher TCK) — the escape hatch.
First-party LadybugDB spike (2026-07-06, v0.18.0, user-directed)
Isolated venv, our workload shape. Full script: scratchpad ladybug-spike/spike.py.
Mechanics (excellent): fresh DB + schema in 0.05s; reopen 0.87s; PK uniqueness enforced (RuntimeError on dup); traversal fine; ORDER BY DESC places nulls FIRST — same semantics as Neo4j Cypher.
Disqualifiers for OUR test fleet (measured, not assumed):
- Single-writer per database, even in-process: 3 of 4 concurrent MERGE threads → "Cannot start a new write transaction. Only one write transaction". Tests that exercise real parallel writers cannot run, let alone pass.
- Schema-first:
CREATE (x:BrandNewLabel)→ Binder exception (every label needs a pre-declared NODE TABLE). Our test_id-tagged ad-hoc nodes = rewrite all. - Verbatim Neo4j-Cypher probes: 5/5 fail — Neo4j-5 constraint DDL (parser),
datetime()(no such function; TIMESTAMP params work), schemaless labels,CALL {}subqueries,shortestPath(). - No cp314/cp314t wheel; sdist fails to build on 3.14 — the suite's free-threaded interpreter cannot import it at all (spike ran on 3.13).
- Footprint reality: 443MB RSS after ~15K nodes (default buffer pool), not the promised megabytes; MERGE throughput ~910/s single-threaded — no write win.
Verdict: a LadybugDB test fleet would be maximal split-brain — tests would no longer exercise the production engine's dialect, schema model, OR concurrency semantics. The Neo4j-clone fleet ruling stands, now empirically. Legitimate future niche: greenfield embedded graph scratch-space (per-run analysis caches), not the system-of-record path and not this suite.
Recommendation
Stay on Neo4j 5.26 Community — deliberately, with two hedges.
Every candidate fails a load-bearing requirement of THIS workload:
- FalkorDB: license (SSPL).
- NebulaGraph: dead OSS branch + no MERGE/constraints/transactions + docs forbidding concurrent UPSERT.
- Apache AGE: right license/governance, wrong Cypher today (ON CREATE SET broken in all releases, zero constraints, zero temporals, PREPARE-only params) and no concurrent MERGE — the exact write pattern.
- LadybugDB: best dialect + unbeatable fleet mechanics, but single-writer per database, 9-month-old fork, no 3.14t wheel (first-party spike above).
Meanwhile Orchestrata's whole feature surface (Bolt + official driver, unique constraints, lock-based concurrent MERGE, datetime() with defined null order, full-text) sits inside CE's GPLv3 set, LTS to 2028-06. CE's gates all have operational answers here: one-DB-per-instance is already the fleet model; offline-dump backup is covered by incus/Btrfs snapshots + periodic dumps; RBAC/clustering unneeded at this scale.
Hedges: (1) ArcadeDB is the designated escape hatch (only Apache-2.0 Bolt engine) — spike it only if a Neo4j Enterprise gate ever actually blocks us. (2) Keep Cypher GQL-convergent and constraints declared in ONE place (done: canonical_schema.py, c295195b) so any future exit is cheap. Re-evaluate at the next Neo4j LTS (2026-11), if AGE ships released ON-CREATE-SET + constraint DDL, or if FalkorDB relicenses.
Appendix A — Memgraph (disqualified: source-available), 4-report synthesis
Researched in depth before the OSS-only scope was set; retained because it calibrates the bar. Version 3.11.0 (2026-06-17), ~6-week release cadence.
License (the disqualifier) — BSL 1.1 as amended 2026-01-01; the text self-declares "not an 'open source' license". Internal production use: free, unlimited. Forbidden: embedding/distribution to third parties, DBaaS, "competing" products. The Jan 2026 amendment quietly DELETED the previous grant's integrated-solution + SaaS clauses (ISV/embedders must now buy an OEM license; changed via GitHub PR, no announcement). Per-version reversion to Apache-2.0 after 4 years (all 2.x already reverted — open source but unsupported). MAGE went Apache-2.0 → BSL in the 2025-11 monorepo merge; mgconsole is GPLv3; Lab is closed freeware ("not licensed for production use" clause). Dynamic algorithms moved into Enterprise at 3.0 (2025-01). Multi-tenancy: Enterprise. Auto-failover: Enterprise (SYNC/ASYNC replication itself is free — more generous than Neo4j CE, which has none).
Technical drop-in verdict — fails even ignoring license:
- Constraint DDL is the OLD Neo4j-3.x dialect (
CREATE CONSTRAINT ON ... ASSERT ...); Neo4j-5FOR ... REQUIREdoes not port; constraints unnamed; unique constraint does NOT create an index (manual index required). - MERGE under concurrency: optimistic snapshot isolation → commit-time "serialization error", client must retry with backoff. Neo4j blocks on locks. Orchestrata's parallel MERGE writers would need a retry layer.
- ORDER BY null placement: undocumented (the exact bug class of the TestRun incident).
- Temporals:
localTime()/localDateTime()camelCase; notime(); ZonedDateTime only since 2.19. - Missing:
COUNT {}/COLLECT {}subqueries,shortestPath()(proprietary[*BFS]instead), pattern-in-functionsize((n)-->()). - Bolt: official neo4j Python driver IS the recommended client (Bolt ≤5.2);
bolt://scheme only for standalone; bookmarks/causal chaining undocumented.
Durability caution: default WAL fsync every 100,000 transactions
(--storage-wal-file-flush-every-n-tx) — committed-transaction loss window on crash
unless set to 1. Snapshots mandatory (WAL-only not possible); snapshot/WAL formats NOT
compatible across versions (dump/load upgrades).
Fleet economics (the part worth envying): ~75 MB idle RSS; ~205–550 MB for our graph size; IN_MEMORY_ANALYTICAL mode (no WAL/deltas/snapshots) is purpose-built for disposable test instances; 220 MB image, non-root (uid 101), healthcheck via mgconsole; tmpfs-friendly.
Vendor risk: ~25–30 staff; $14.2M total funding, none since 2023-12, no Series A; hard pivot to GraphRAG/agentic-AI; single-vendor development (no community commits to speak of); 4.2K stars / 2.7K Discord.
Appendix B — AWS Neptune (disqualified: proprietary managed service)
Not open source in any form, no self-hosting, openCypher dialect without schema constraints, and cloud cost per instance-hour is structurally wrong for a run-dozens- of-times-daily local test fleet. Ruled out on scope; not researched further.