$npx -y skills add neo4j-contrib/neo4j-skills --skill neo4j-migration-skillMigrates Neo4j driver code and Cypher queries from older versions (4.x, 5.x)
| 1 | ## When to Use |
| 2 | - Upgrading driver dependency from 4.x or 5.x to 6.x |
| 3 | - Migrating Cypher queries to Cypher 25 syntax |
| 4 | - Fixing deprecated API warnings after a driver or Neo4j version bump |
| 5 | - Auditing a codebase for removed/deprecated Neo4j APIs before upgrading |
| 6 | |
| 7 | ## When NOT to Use |
| 8 | - **Writing new Cypher queries** → `neo4j-cypher-skill` |
| 9 | - **DB admin** (backup, restore, import, cypher-shell) → `neo4j-cli-tools-skill` |
| 10 | - **Starting fresh** → `neo4j-getting-started-skill` |
| 11 | - **GDS algorithm migration** — not covered here; consult GDS release notes |
| 12 | |
| 13 | --- |
| 14 | |
| 15 | ## Entry Criteria |
| 16 | |
| 17 | Before starting, ask: |
| 18 | 1. **Target Neo4j version** — needed to select Cypher dialect and driver version |
| 19 | 2. **Languages in use** — scan `package.json`, `requirements.txt`, `pom.xml`, `*.csproj`, `go.mod` |
| 20 | 3. **Current driver versions** — read from dependency files; do NOT guess |
| 21 | |
| 22 | If target is >= 2025.06: ask whether Cypher 5 or Cypher 25 dialect will be used (both supported; Cypher 25 is the new default). |
| 23 | |
| 24 | --- |
| 25 | |
| 26 | ## Step 1 — Scan Codebase |
| 27 | |
| 28 | ```bash |
| 29 | # Find Cypher strings (queries embedded in source) |
| 30 | grep -rn "MATCH\|MERGE\|CREATE\|CALL\|RETURN" --include="*.py" --include="*.js" \ |
| 31 | --include="*.ts" --include="*.java" --include="*.cs" --include="*.go" \ |
| 32 | --include="*.cypher" --include="*.cql" . | grep -v ".git" |
| 33 | |
| 34 | # Find dependency files |
| 35 | find . -name "requirements*.txt" -o -name "package.json" -o -name "pom.xml" \ |
| 36 | -o -name "*.csproj" -o -name "go.mod" | grep -v ".git" | grep -v node_modules |
| 37 | ``` |
| 38 | |
| 39 | Collect findings before modifying anything. List all deprecated patterns found. |
| 40 | |
| 41 | --- |
| 42 | |
| 43 | ## Step 2 — Cypher Migration (4.x / 5.x → Cypher 25) |
| 44 | |
| 45 | Apply to every Cypher string, `.cypher` file, OGM/SDN `@Query` annotation, and template literal. |
| 46 | |
| 47 | ### Complete Substitution Table |
| 48 | |
| 49 | | Old syntax | Cypher 25 replacement | Notes | |
| 50 | |---|---|---| |
| 51 | | `[:REL*1..5]` | `(()-[:REL]->()){1,5}` | QPE quantifier group | |
| 52 | | `[:REL*]` | `(()-[:REL]->()){1,}` | Unbounded QPE | |
| 53 | | `[:REL*0..5]` | `(()-[:REL]->()){0,5}` | Zero-hop allowed | |
| 54 | | `shortestPath((a)-[*]->(b))` | `SHORTEST 1 (a)(()-[]->()){1,}(b)` | QPE shortest path | |
| 55 | | `allShortestPaths((a)-[*]->(b))` | `ALL SHORTEST (a)(()-[]->()){1,}(b)` | QPE all-shortest | |
| 56 | | `id(n)` | `elementId(n)` | Returns string, not int | |
| 57 | | `CALL { WITH x ... }` | `CALL (x) { ... }` | Explicit import syntax | |
| 58 | | `PERIODIC COMMIT` | `CALL (...) { ... } IN TRANSACTIONS OF 1000 ROWS` | Batched writes | |
| 59 | | `-- comment` | `// comment` | SQL comment invalid | |
| 60 | | `SET n = r` (structural val) | `SET n = properties(r)` | Extract map first | |
| 61 | | `MERGE (a {x:1})-[:T]->(b {x:a.x})` | Rewrite — cross-entity MERGE refs disallowed | Split into MATCH+MERGE | |
| 62 | | `CREATE INDEX ... OPTIONS { indexProvider: ... }` | Remove `indexProvider` from OPTIONS | Provider selection removed | |
| 63 | | `db.create.setVectorProperty(...)` | Use native VECTOR property type | Procedure removed | |
| 64 | | `dbms.upgrade()` / `dbms.upgradeStatus()` | Use `cypher-shell :sysinfo` | Procedures removed | |
| 65 | | `USE composite.'1'` | `` USE `composite.1` `` | Backtick entire qualified name | |
| 66 | | `RETURN 1 as my$Identifier` | `` RETURN 1 as `my$Identifier` `` | `$` removed from unescaped ids | |
| 67 | |
| 68 | ### Vector Index Queries (version-branched) |
| 69 | |
| 70 | | Version | Syntax | |
| 71 | |---|---| |
| 72 | | Neo4j < 2026.01 | `CALL db.index.vector.queryNodes(idx, k, $emb) YIELD node, score` | |
| 73 | | Neo4j >= 2026.01 | `SEARCH n IN (VECTOR INDEX idx FOR $emb LIMIT k) SCORE AS score` | |
| 74 | |
| 75 | ### Cypher Dialect Prefix Rule |
| 76 | |
| 77 | - Target >= 2025.06, dialect = Cypher 25: prepend `CYPHER 25` to every top-level query |
| 78 | - Target >= 2025.06, dialect = Cypher 5: prepend `CYPHER 5` (keeps deprecated forms working) |
| 79 | - Target 4.x or 5.x: no prefix needed; fetch changelog per [references/cypher-queries.md](references/cypher-queries.md) |
| 80 | |
| 81 | ### `id(n)` → `elementId(n)` Caveats |
| 82 | |
| 83 | `elementId()` 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. |
| 84 | |
| 85 | ```diff |
| 86 | - WHERE id(n) = $nodeId # $nodeId was integer |
| 87 | + WHERE elementId(n) = $nodeId # $nodeId must now be string |
| 88 | ``` |
| 89 | |
| 90 | --- |
| 91 | |
| 92 | ## Step 3 — Driver Migration |
| 93 | |
| 94 | Pick the section(s) matching languages found in Step 1. |
| 95 | |
| 96 | --- |
| 97 | |
| 98 | ### Python Driver (5.x → 6.x) |
| 99 | |
| 100 | **Min requirements**: Python >= 3.10, `neo4j` package (6.0+, released Jan 12 2026) |
| 101 | |
| 102 | #### P |