Migrate from Neo4j to ArcadeDB

Your Cypher queries work as-is. ArcadeDB's native OpenCypher engine has passed 97.8% of the official TCK with zero failures. Add multi-model, embedded mode, and 6 query languages — all under the Apache 2.0 license.

*Neo4j, Cypher, OpenCypher and APOC are registered trademarks of Neo4j, Inc.

ArcadeDB vs Neo4j in a nutshell

Neo4j ArcadeDB
Data Models Graph only Graph + Document + Key/Value + Search + Vector
Query Languages Cypher Cypher + SQL + Gremlin + GraphQL + MongoDB QL + Redis
BOLT Protocol Native Compatible (v3.0, v4.0, v4.4)
OpenCypher TCK Reference impl. 97.8% pass rate (0 failures)
HA / Replication Enterprise only ($) Built-in (free)
License GPL / Commercial Apache 2.0 (free for commercial use)

Apache 2.0 vs GPL: What It Means for Your Business

This matters more than most people realize. Neo4j Community Edition is licensed under GPL (GNU General Public License), a copyleft license. If you distribute software that includes or links to GPL code, your entire application must also be released under GPL — meaning you must publish your source code. For most commercial products, this is a non-starter. The alternative is paying for Neo4j's commercial Enterprise license.


ArcadeDB is licensed under Apache 2.0, a permissive license. You can embed ArcadeDB in proprietary software, modify it, distribute it, and sell products built on it — with no obligation to open-source your code. No license fees, no usage limits, no "call us for Enterprise pricing." Every feature, including HA replication and clustering, is available to everyone under the same permissive license. But licensing is just the beginning.

Why Move to ArcadeDB

True Multi-Model

Neo4j is graph-only. ArcadeDB natively supports 5 data models in one engine: Graph, Document, Key/Value, Full-Text Search, and Vector Embeddings. The same record can be a vertex and a document — no duplication.

6 Query Languages

Neo4j speaks Cypher only. ArcadeDB speaks OpenCypher, SQL, Gremlin, GraphQL, MongoDB QL, and Redis on the same data. Keep your Cypher queries and add SQL for analytics.

Embedded Mode

Run ArcadeDB inside your JVM process with zero network overhead. Ideal for microservices, edge computing, testing, and batch processing. Scale to server mode when ready.

BOLT Protocol

Use the official Neo4j drivers for Java, Python, JavaScript, .NET, and Go to connect to ArcadeDB. Change the connection URL and credentials — your code stays the same.

Performance Built In

Statement & plan caching, cost-based optimizer, async API, LSM-Tree indexes, and minimal GC pressure. Designed for millions of records per second.

HA/Replication Included

Neo4j reserves clustering for its paid Enterprise edition. ArcadeDB includes leader-follower replication and automatic failover in the open-source distribution at no cost.

Step 1: Migrate Your Data with the Built-in Importer

ArcadeDB ships a dedicated Neo4j Importer that reads a Neo4j database exported in JSONL format and creates a fully indexed ArcadeDB database. No manual schema creation, no scripting — it handles everything automatically.

Export from Neo4j

Use the APOC library to export your Neo4j database:

CALL apoc.export.json.all("neo4j-export.jsonl", {})

This produces a JSONL file (one JSON object per line) containing all nodes and relationships:

{"type":"node","id":"0","labels":["User"],"properties":{"born":"2015-07-04T19:32:24","name":"Adam","age":42}}
{"type":"node","id":"1","labels":["User"],"properties":{"name":"Jim","age":42}}
{"type":"relationship","label":"KNOWS","properties":{"since":1993},"start":{"id":"0","labels":["User"]},"end":{"id":"1","labels":["User"]}}

Import into ArcadeDB

The simplest way is through the ArcadeDB Console:

> CREATE DATABASE MyDatabase
{MyDatabase}> IMPORT DATABASE file:///path/to/neo4j-export.jsonl

The importer runs a three-pass process:

Import via Java API

For programmatic migrations, use the Neo4jImporter class directly:

Neo4jImporter importer = new Neo4jImporter(
    "-i", "/path/to/neo4j-export.jsonl",
    "-d", "./databases/MyDatabase",
    "-o"  // overwrite if exists
);
importer.run();

How Multi-Label Nodes Are Handled

Neo4j supports multiple labels per node (e.g., a node can be both User and Administrator). ArcadeDB requires each vertex to have exactly one type, so the importer handles this elegantly using type inheritance.

A Neo4j node with labels ["User", "Administrator"] becomes a vertex of type Administrator~User (labels sorted alphabetically, joined with ~) that extends both Administrator and User types. The tilde separator avoids conflicts with user type names that may contain underscores.

This means:

Step 2: Adapt Your Java Code

Your Cypher queries work as-is in ArcadeDB — the native OpenCypher engine is TCK-compliant. What changes is the surrounding Java code: how you open the database, manage transactions, and (optionally) use the Java API for performance-critical paths.

Database Setup

Neo4j

Driver driver = GraphDatabase.driver("bolt://localhost:7687",
    AuthTokens.basic("neo4j", "password"));
Session session = driver.session();

ArcadeDB (embedded — recommended)

Database database = new DatabaseFactory("./databases/mydb").open();

ArcadeDB (via BOLT — drop-in replacement)

// Same Neo4j driver, just change the URL and credentials
Driver driver = GraphDatabase.driver("bolt://localhost:7687",
    AuthTokens.basic("root", "arcadedb_password"),
    Config.builder().withoutEncryption().build());
Session session = driver.session(SessionConfig.forDatabase("mydb"));
// From here on, your existing code works unchanged

If you go with BOLT, your Cypher code stays identical. The rest of this section covers the embedded Java API for those who want maximum performance.

Schema Creation

Neo4j (Cypher)

CREATE CONSTRAINT FOR (p:Person) REQUIRE p.id IS UNIQUE

ArcadeDB (SQL)

CREATE VERTEX TYPE Person
CREATE EDGE TYPE KNOWS
CREATE PROPERTY Person.id LONG
CREATE INDEX ON Person (id) UNIQUE

The syntax is close to Neo4j's but more explicit: you define vertex and edge types separately, then add properties and indexes. This also gives you schema validation that Neo4j doesn't enforce by default.

Creating Vertices and Edges

Where Neo4j requires the driver and Cypher even for simple operations, ArcadeDB's embedded Java API gives you direct, type-safe access:

database.transaction(() -> {
    MutableVertex alice = database.newVertex("Person");
    alice.set("name", "Alice");
    alice.set("born", 1985);
    alice.save();

    MutableVertex bob = database.newVertex("Person");
    bob.set("name", "Bob");
    bob.set("born", 1990);
    bob.save();

    // Create an edge with properties -- one line
    alice.newEdge("KNOWS", bob, "since", 2015);
});

Querying

Neo4j

Result result = session.run(
    "MATCH (p:Person)-[:KNOWS]->(friend) WHERE p.name = $name RETURN friend.name AS name",
    Map.of("name", "Alice"));
while (result.hasNext()) {
    Record record = result.next();
    System.out.println(record.get("name").asString());
}

ArcadeDB (direct graph traversal — zero parsing overhead)

Vertex alice = database.lookupByKey("Person", "name", "Alice").next().asVertex();
for (Vertex friend : alice.getVertices(Vertex.DIRECTION.OUT, "KNOWS"))
    System.out.println(friend.getString("name"));

You can also mix: use Cypher for complex pattern matching and the Java API for hot-path traversals.

Transactions

Neo4j

try (Transaction tx = session.beginTransaction()) {
    tx.run("CREATE (p:Person {name: 'Charlie'})");
    tx.run("MATCH (a:Person {name: 'Alice'}), (c:Person {name: 'Charlie'}) CREATE (a)-[:KNOWS]->(c)");
    tx.commit();
}

ArcadeDB

database.transaction(() -> {
    MutableVertex charlie = database.newVertex("Person");
    charlie.set("name", "Charlie");
    charlie.save();

    Vertex alice = database.lookupByKey("Person", "name", "Alice").next().asVertex();
    alice.asVertex().newEdge("KNOWS", charlie);
});

Bulk Loading

Neo4j requires USING PERIODIC COMMIT or the neo4j-admin import tool. ArcadeDB provides a native asynchronous API:

database.async().onError(exception -> exception.printStackTrace());

for (int i = 0; i < 1_000_000; i++) {
    MutableVertex v = database.newVertex("Person");
    v.set("id", i);
    v.set("name", "Person_" + i);
    database.async().createRecord(v, null);
}

Ready to Migrate?

Export your Neo4j database, run the built-in importer, and your Cypher queries work as-is. It's that simple.