Write Cypher queries with proper patterns for merging, traversal, and performance.
Scanned 9/6/2026
Install to Claude Code
npx -y skills add clawic/skills --skill neo4j --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Neo4j?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/clawic-neo4j)More formats (shields.io, HTML) on the badges page.
---
name: Neo4j
slug: neo4j
version: 1.0.0
description: Write Cypher queries with proper patterns for merging, traversal, and performance.
homepage: https://clawic.com/skills/neo4j
metadata:
clawdbot:
emoji: 🕸️
requires:
anyBins:
- cypher-shell
- neo4j
os:
- linux
- darwin
- win32
displayName: Neo4j
---
## MERGE Trap
- `MERGE` matches the FULL pattern—`MERGE (a)-[:KNOWS]->(b)` creates duplicates if relationship missing
- Safe upsert: merge nodes separately, then merge relationship
- Use `ON CREATE SET` and `ON MATCH SET` for conditional properties—without these, nothing updates on match
- For simple node upsert: `MERGE (n:User {id: $id})` with unique constraint on id
## Indexes
- No index on property = full label scan—always index properties used in WHERE
- Unique constraint auto-creates index—prefer constraint over plain index when applicable
- Check plan with `EXPLAIN` before production—look for "NodeByLabelScan" without filter pushdown
- Text search needs full-text index: `CREATE FULLTEXT INDEX FOR (n:Post) ON EACH [n.title, n.body]`
## Variable-Length Paths
- Unbounded `[*]` explodes on connected graphs—always set upper bound `[*1..5]`
- `[*0..]` includes start node—usually unintended, start from `[*1..]`
- `shortestPath()` returns one path only—use `allShortestPaths()` for all equally short paths
- Filter inside path is expensive: `[r:KNOWS* WHERE r.active]` scans then filters—consider data model change
## Cartesian Product
- Two disconnected patterns multiply: `MATCH (a:User), (b:Product)` returns rows × rows
- Connect patterns or split with WITH—unintended cartesian kills performance
- Same variable in two patterns = implicit join, no cartesian
- `PROFILE` query shows "CartesianProduct" operator when it happens
## WITH Scope Reset
- Only variables in WITH carry forward—`MATCH (a)--(b) WITH a` loses `b`
- Aggregation forces WITH: `MATCH (u:User) WITH u.country AS c, count(*) AS n`
- Common mistake: filtering after aggregation requires second WITH
- Pagination: `WITH n ORDER BY n.created SKIP 10 LIMIT 10`
## NULL Propagation
- `OPTIONAL MATCH` returns NULL for missing patterns—NULLs propagate through expressions
- `WHERE` after OPTIONAL MATCH filters out NULLs—use `COALESCE()` to preserve rows
- `count(NULL)` returns 0—useful: `OPTIONAL MATCH (u)-[:REVIEWED]->(p) RETURN count(p)`
- Property access on NULL throws no error, returns NULL—silent data loss
## Direction
- Query direction ignored with no arrow: `(a)-[:KNOWS]-(b)` matches both ways
- Creation requires direction—must pick one, can't create undirected
- Wrong direction = empty results—if relationship is `(a)-[:OWNS]->(b)`, query `(b)-[:OWNS]->(a)` finds nothing
## Batch Operations
- Large creates in single transaction exhaust heap—use `CALL {} IN TRANSACTIONS OF 1000 ROWS`
- `UNWIND $list AS item CREATE (n:Node {id: item.id})` for batch inserts
- `apoc.periodic.iterate()` for complex batch logic with progress
- Delete in batches: `MATCH (n:Old) WITH n LIMIT 10000 DETACH DELETE n` in loop
## Parameter Injection
- Always use parameters `$param` not string concatenation—prevents Cypher injection
- Parameters also enable query plan caching—literal values recompile each time
- Pass as map: `{param: value}` in driver, `:param {param: value}` in browser
- List parameter for IN: `WHERE n.id IN $ids`
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!