Neo4j 4.4 to 5.x upgrades are a significant jump, and the biggest surprise is how much the underlying query language engine has changed, making some of your old Cypher queries silently return different results or error out entirely.
Let’s see what a typical migration looks like. Imagine we have a simple graph with Person nodes and LIKES relationships.
// In Neo4j 4.4
MATCH (p:Person)
RETURN p.name, p.age;
MATCH (p1:Person)-[:LIKES]->(p2:Person)
RETURN p1.name AS giver, p2.name AS receiver;
Now, let’s simulate a migration. We’ll set up a small graph and then attempt to run the same queries in a Neo4j 5 environment after a hypothetical migration.
First, the setup in Neo4j 4.4:
CREATE (alice:Person {name: 'Alice', age: 30})
CREATE (bob:Person {name: 'Bob', age: 25})
CREATE (charlie:Person {name: 'Charlie', age: 35})
CREATE (alice)-[:LIKES]->(bob)
CREATE (bob)-[:LIKES]->(charlie)
CREATE (charlie)-[:LIKES]->(alice);
If you were to run the p.age query in Neo4j 5 without any migration steps, you might get an error like: Invalid input 'a': expected ')' or whitespace if you tried to access p.age directly as a property. This is because Neo4j 5 has moved towards more explicit property access.
The core problem Neo4j 5 addresses is the ambiguity and potential for performance issues in how graph data is accessed and updated. It introduces a more robust and predictable query execution plan by making property access explicit. This means you can’t just assume a property exists and is of a certain type; you need to declare it.
Here’s how you’d typically migrate your data and queries:
-
Backup Your Database: Always start with a full backup. Use
neo4j-admin dumpor your cloud provider’s backup mechanism. -
Update Neo4j Version: Stop your Neo4j 4.4 instance and install Neo4j 5.x.
-
Run the
neo4j-migrateTool: This is the primary tool for handling breaking changes. You’ll typically run this from your Neo4j installation’sbindirectory.# Navigate to your Neo4j 5.x bin directory cd /path/to/neo4j-5.x/bin # Run the migration tool ./neo4j-migrate upgrade --from-path /path/to/neo4j-4.4.x/data/databases/graph.db --to-path /path/to/neo4j-5.x/data/databases/graph.dbThis tool analyzes your database and attempts to automatically convert incompatible parts of your data and schema to the Neo4j 5 format. It’s not magic; it handles common cases, but complex queries or custom procedures might still need manual intervention.
-
Address Cypher Breaking Changes: This is where most of the work is.
-
Property Access: The most common breaking change is how properties are accessed. In Neo4j 4.4,
p.agewas often sufficient. In Neo4j 5, you’ll often need to be more explicit, especially if you’re dealing with potentialnullvalues or different data types. For example, ifagewas a property, you might need to ensure it’s treated as a number.- Diagnosis: Run your queries against the migrated database. Look for errors like
Invalid input 'a': expected ')' or whitespaceorType mismatch: expected Integer but was String. - Fix: Use explicit casting or property checking. For
age, you’d likely changep.agetotoInteger(p.age)orp.age IS NOT NULLif you want to avoid errors with missing properties.// In Neo4j 5 MATCH (p:Person) WHERE p.age IS NOT NULL RETURN p.name, toInteger(p.age); // Explicitly cast to Integer - Why it works: Neo4j 5’s query engine is stricter about types and property existence to prevent runtime errors and ensure predictable query plans. Explicit casting or checking ensures that you’re always working with the expected data type and that missing properties don’t cause unexpected behavior.
- Diagnosis: Run your queries against the migrated database. Look for errors like
-
Implicit
RETURN: In Neo4j 4.4,MATCH (n) RETURN nwould return the entire node, including all its properties. In Neo4j 5, this is no longer the default for performance and clarity.- Diagnosis: Queries that previously returned entire nodes might now return nothing or throw errors related to missing return items.
- Fix: Explicitly return the properties you need.
// In Neo4j 5 MATCH (p:Person) RETURN p.name, p.age; // Explicitly return name and age - Why it works: By forcing explicit returns, Neo4j 5 ensures that queries only fetch the data they absolutely require, leading to better performance and reduced network traffic.
-
Procedure Signatures: If you use any APOC or custom procedures, their signatures might have changed.
- Diagnosis: Errors like
Unknown procedure ...orProcedure ... requires N arguments but received M. - Fix: Consult the documentation for the specific procedures you’re using and update your calls to match the new signatures. For example,
apoc.create.nodemight have changed its argument order or required explicit types. - Why it works: Procedure APIs are updated to align with Neo4j 5’s core changes, often requiring more specific input parameters for robustness.
- Diagnosis: Errors like
-
Index and Constraint Syntax: While largely backward compatible, some very old syntax might be deprecated.
- Diagnosis: Deprecation warnings or errors related to index/constraint creation.
- Fix: Use the modern syntax. For example,
CREATE INDEX ON :Person(name)is preferred over older forms. - Why it works: Neo4j standardizes its DDL (Data Definition Language) for better consistency and future extensibility.
-
Security and Authentication: Neo4j 5 has enhanced security features, which might require updates to authentication configurations or user management.
- Diagnosis: Connection refused errors, authentication failures, or messages about unsupported authentication methods.
- Fix: Update your
neo4j.conffile with the new security settings, especiallydbms.security.auth_enabledand related parameters. Consider migrating to RBAC (Role-Based Access Control) if you haven’t already. - Why it works: Neo4j 5 prioritizes a more secure default configuration and offers more granular access control, requiring explicit configuration for authentication and authorization.
-
-
Test Thoroughly: Run your application’s test suite against the migrated database. Pay close attention to queries that involve property access, aggregations, and any custom procedures.
After a successful migration, you’ll find that your queries are more predictable and that Neo4j 5’s performance optimizations can be fully leveraged. The next hurdle you’ll likely encounter is understanding the new Fabric and multi-database capabilities.