Use when upgrading Neo4j drivers to new major versions
neo4j-cypher-skillneo4j-cli-tools-skillneo4j-getting-started-skillBefore starting, ask:
package.json, requirements.txt, pom.xml, *.csproj, go.modIf target is >= 2025.06: ask whether Cypher 5 or Cypher 25 dialect will be used (both supported; Cypher 25 is the new default).
# Find Cypher strings (queries embedded in source)
grep -rn "MATCH\|MERGE\|CREATE\|CALL\|RETURN" --include="*.py" --include="*.js" \
--include="*.ts" --include="*.java" --include="*.cs" --include="*.go" \
--include="*.cypher" --include="*.cql" . | grep -v ".git"
# Find dependency files
find . -name "requirements*.txt" -o -name "package.json" -o -name "pom.xml" \
-o -name "*.csproj" -o -name "go.mod" | grep -v ".git" | grep -v node_modules
Collect findings before modifying anything. List all deprecated patterns found.
Apply to every Cypher string, .cypher file, OGM/SDN @Query annotation, and template literal.
| Old syntax | Cypher 25 replacement | Notes |
|---|---|---|
[:REL*1..5] |
(()-[:REL]->()){1,5} |
QPE quantifier group |
[:REL*] |
(()-[:REL]->()){1,} |
Unbounded QPE |
[:REL*0..5] |
(()-[:REL]->()){0,5} |
Zero-hop allowed |
shortestPath((a)-[*]->(b)) |
SHORTEST 1 (a)(()-[]->()){1,}(b) |
QPE shortest path |
allShortestPaths((a)-[*]->(b)) |
ALL SHORTEST (a)(()-[]->()){1,}(b) |
QPE all-shortest |
id(n) |
elementId(n) |
Returns string, not int |
CALL { WITH x ... } |
CALL (x) { ... } |
Explicit import syntax |
PERIODIC COMMIT |
CALL (...) { ... } IN TRANSACTIONS OF 1000 ROWS |
Batched writes |
-- comment |
// comment |
SQL comment invalid |
SET n = r (structural val) |
SET n = properties(r) |
Extract map first |
MERGE (a {x:1})-[:T]->(b {x:a.x}) |
Rewrite β cross-entity MERGE refs disallowed | Split into MATCH+MERGE |
CREATE INDEX ... OPTIONS { indexProvider: ... } |
Remove indexProvider from OPTIONS |
Provider selection removed |
db.create.setVectorProperty(...) |
Use native VECTOR property type | Procedure removed |
dbms.upgrade() / dbms.upgradeStatus() |
Use cypher-shell :sysinfo |
Procedures removed |
USE composite.'1' |
USE `composite.1` |
Backtick entire qualified name |
RETURN 1 as my$Identifier |
RETURN 1 as `my$Identifier` |
$ removed from unescaped ids |
| Version | Syntax |
|---|---|
| Neo4j < 2026.01 | CALL db.index.vector.queryNodes(idx, k, $emb) YIELD node, score |
| Neo4j >= 2026.01 | SEARCH n IN (VECTOR INDEX idx FOR $emb LIMIT k) SCORE AS score |
CYPHER 25 to every top-level queryCYPHER 5 (keeps deprecated forms working)id(n) β elementId(n) CaveatselementId() returns a string (e.g., "4:abc123:0"), not an integer. Fix downstream code that stores or compares it as int. Do NOT use elementId() values for numeric operations.
- WHERE id(n) = $nodeId # $nodeId was integer
+ WHERE elementId(n) = $nodeId # $nodeId must now be string
Pick the section(s) matching languages found in Step 1.
Min requirements: Python >= 3.10, neo4j package (6.0+, released Jan 12 2026)
# requirements.txt
- neo4j-driver>=5.0.0
+ neo4j>=6.0.0
neo4j-driver package is deprecated since 6.0 and receives no further updates.
| Old | New | Notes |
|---|---|---|
session.read_transaction(fn) |
session.execute_read(fn) |
|
session.write_transaction(fn) |
session.execute_write(fn) |
|
session.last_bookmark() |
session.last_bookmarks() |
Returns Bookmarks (plural) |
Bookmark class |
Bookmarks class |
|
TRUST_ALL_CERTIFICATES |
trusted_certificates=TrustAll() |
|
TRUST_SYSTEM_CA_SIGNED_CERTIFICATES |
trusted_certificates=TrustSystemCAs() |
|
neo4j.conf, neo4j.data modules |
Removed β use top-level neo4j.* |
Drivers and sessions no longer auto-close on GC. Add explicit cleanup:
- driver = GraphDatabase.driver(URI, auth=(USER, PASS))
- # used without explicit close
+ with GraphDatabase.driver(URI, auth=(USER, PASS)) as driver:
+ with driver.session(database="neo4j") as session:
+ ...
Or call .close() explicitly. Repeated .close() is a no-op.
| Old exception | New exception | Trigger |
|---|---|---|
ClientError (for timeout) |
ConnectionAcquisitionTimeoutError |
Acquisition timeout |
AuthError (invalid config) |
ConfigurationError |
Invalid auth params |
ValueError raised for Query obj |
TypeError |
Passing Query to Transaction.run |
execute_query(), GraphDatabase.driver(), neo4j+s:// URI, auth=(user, pw), session run().
Full changelog: references/python-driver.md
Min requirements: Node.js >= 18 (check engines in driver's package.json); package neo4j-driver
| Old | New | Notes |
|---|---|---|
session.readTransaction(fn) |
session.executeRead(fn) |
|
session.writeTransaction(fn) |
session.executeWrite(fn) |
|
session.lastBookmark() |
session.lastBookmarks() |
Returns array |
resultSummary.updateStatistics |
resultSummary.counters |
|
driver.verifyConnectivity() β ServerInfo |
driver.getServerInfo() β ServerInfo |
verifyConnectivity() now returns void |
| Old | New |
|---|---|
isRetriableError(err) |
isRetryable(err) |
neo4jError.retriable |
neo4jError.retryable |
notificationCategory |
notificationClassification |
Neo4j integers map to neo4j.Integer (64-bit). Use .toNumber() or .toInt() for arithmetic. Large values (> 2^53) lose precision β store as string with .toString().
// Safe pattern
const count = record.get('count').toNumber()
Full changelog: references/javascript-driver.md
Min requirements: Java 21; Maven org.neo4j.driver:neo4j-java-driver:6.x
<dependency>
<groupId>org.neo4j.driver</groupId>
<artifactId>neo4j-java-driver</artifactId>
- <version>5.x.x</version>
+ <version>6.0.0</version>
</dependency>
| Removed | Replacement | Notes |
|---|---|---|
RxSession / RxTransaction |
Use async AsyncSession or sync Session |
Reactive API removed |
Bookmark multi-value constructor |
Bookmark.from(iterable) |
|
session.readTransaction(fn) |
session.executeRead(fn) |
|
session.writeTransaction(fn) |
session.executeWrite(fn) |
|
TrustStrategy.certFile() |
TrustStrategy.trustCustomCertificateSignedBy(path) |
|
Notification.severity() |
Notification.severityLevel() |
Returns typed enum |
neo4j-java-driver-bom no longer imports netty-bom as of 6.0.1. If using Netty native transport, add explicit netty-bom import.
Legacy Logging API deprecated β configure System.Logger instead.
Full changelog: references/java-driver.md
Min requirements: .NET 8, 9, or 10 (.NET Standard 2.1 dropped); NuGet Neo4j.Driver 6.x
- <PackageReference Include="Neo4j.Driver" Version="5.*" />
+ <PackageReference Include="Neo4j.Driver" Version="6.*" />
Neo4j.Driver.Signed no longer receives updates β switch to Neo4j.Driver (now signed).
| Removed | Replacement | Notes |
|---|---|---|
ILogger |
INeo4jLogger |
Interface renamed |
ConfigBuilder.WithIpv6Enabled() |
Remove call β IPv6 always enabled | |
Config.Ipv6Enabled property |
Remove β always true | |
| Simple driver | Use standard IDriver |
Removed entirely |
Full changelog: references/dotnet-driver.md
Min requirements: Go 1.24; module github.com/neo4j/neo4j-go-driver/v6
- require github.com/neo4j/neo4j-go-driver/v5 v5.x.x
+ require github.com/neo4j/neo4j-go-driver/v6 v6.x.x
Update all imports from /v5/ to /v6/.
| Old | New | Notes |
|---|---|---|
neo4j.NewDriver(...) |
neo4j.NewDriverWithContext(...) |
Context-aware; or just use neo4j.NewDriver (now has context) |
neo4j.Config struct |
config.Config |
Import github.com/neo4j/neo4j-go-driver/v6/neo4j/config |
neo4j.ServerAddressResolver |
config.ServerAddressResolver |
|
neo4j.LogLevel / neo4j.ERROR etc. |
log.Level / log.ERROR |
Import neo4j/log sub-package |
log.Console |
log.ToConsole |
|
log.Void |
log.ToVoid |
|
neo4j.Single[T] |
neo4j.SingleT[T] (still present; context variant preferred) |
|
neo4j.Driver interface |
neo4j.DriverWithContext |
*WithContext variants are now primary |
neo4j.Session interface |
neo4j.SessionWithContext |
|
Config.RootCAs field |
Config.TlsConfig |
Pass *tls.Config directly |
| Notification constants (old pkg) | notifications.* equivalents |
Import neo4j/notifications |
In v6, neo4j.NewDriverWithContext is the canonical constructor. The old *WithContext method names are deprecated (targeted for removal in v7) β base names now include context by default.
- driver, err := neo4j.NewDriver(uri, neo4j.BasicAuth(user, pass, ""))
+ driver, err := neo4j.NewDriverWithContext(uri, neo4j.BasicAuth(user, pass, ""))
Full migration guide: references/go-driver.md
| Neo4j version | Cypher dialect | Driver 6.x compatible | Notes |
|---|---|---|---|
| 4.4 LTS | Cypher 4 | Yes (bolt compat) | Support ended Nov 2025 |
| 5.26 LTS | Cypher 5 | Yes | Supported until Nov 2028 |
| 2025.01β2025.05 | Cypher 5 | Yes | CalVer era begins |
| 2025.06+ | Cypher 5 or 25 | Yes | Cypher 25 new default |
| 2026.01+ | Cypher 25 | Yes | SEARCH clause available |
| 2026.07.0 | Cypher 25 | Yes | Skip this patch β block-format UTF-8 regression makes trim() fail queries and corrupt stored strings; upgrade target is 2026.07.1 |
| 2026.08+ | Cypher 25 | Yes | UUID type + string interpolation added; UUID properties require driver >= 6.2 (Python >= 6.3) β older drivers return placeholder MAP and warn 03N95; 2026.08 bundles Java driver 6.2.1; skip 2026.08.0 (query-failure bug) β target 2026.08.1+ |
| 2026.09+ | Cypher 25 | Yes | SEARCH clause accepts FULLTEXT INDEX; page cache reserves full server.memory.pagecache.size at startup |
Store format: no changes between 4.4 and 2026.x. block format default for new Enterprise dbs since 5.22. high_limit and standard deprecated in 5.23, removed after 2026 LTS β Neo4j refuses to start on a high_limit store after that LTS; run offline neo4j-admin database migrate --to-format=block <db> on or before the LTS.
Server JVM: 2026.x runs on Java SE 21 or 25; Java 21 support ends with the 2026 LTS β move servers to Java 25 [2026.08 deprecation].
No downgrades supported β take a backup before any server upgrade.
# Python: run with dev mode to surface all deprecation warnings
python -W error::DeprecationWarning -m pytest tests/
# JS: run tests
npm test
# Java
mvn test
# .NET
dotnet test
# Go
go test ./...
After test run: if any DeprecationWarning or deprecated-API log appears, treat as ERROR β fix before proceeding.
For Cypher: run each migrated query through EXPLAIN first:
# Via Query API v2
curl -X POST https://<host>/db/<database>/query/v2 \
-u <user>:<password> -H "Content-Type: application/json" \
-d '{"statement": "EXPLAIN <your query>"}'
| Error | Cause | Fix |
|---|---|---|
id(n) returns string, int comparison fails |
elementId() returns string |
Update stored IDs to string; fix WHERE clauses |
Cannot merge node using null property value |
MERGE key resolved to null | Validate params before MERGE |
Neo4j.Driver.Exceptions.AuthenticationException |
Wrong credential config after .NET rename | Update INeo4jLogger usage; verify config |
TypeError: neo4j-driver is deprecated |
Old package installed | Replace with neo4j>=6.0.0 in requirements |
AttributeError: 'Session' has no 'read_transaction' |
Python 5β6, method removed | Replace with execute_read() |
RxSession not found |
Java 6.x, Reactive API removed | Migrate to async or sync session |
undefined is not a function (.readTransaction) |
JS 6.x, method removed | Replace with executeRead() |
Go: undefined: neo4j.Config |
v5 import path still present | Update all imports to /v6/ |
PERIODIC COMMIT not supported |
Cypher 25, clause removed | Use CALL (...) IN TRANSACTIONS |
Unknown function id() |
id() removed in Cypher 25 | Replace with elementId() |
Load on demand β high discovery rate because explicitly linked:
For any syntax not covered above, fetch:
https://neo4j.com/docs/cypher-manual/25/deprecations-additions-removals-compatibility/
id(n) β elementId(n) and downstream intβstring conversions fixedPERIODIC COMMIT β CALL IN TRANSACTIONS in all batch writesCALL { WITH x ... } β CALL (x) { ... } in all subqueriesneo4j-driver β neo4j)read_transaction/readTransaction β execute_read/executeRead).close())last_bookmark β last_bookmarks, Bookmark β Bookmarks)/v5/ to /v6/; neo4j.Config β config.ConfigILogger β INeo4jLogger; Neo4j.Driver.Signed β Neo4j.DriverEXPLAIN run on all migrated Cypher queries; no errors