neo4j-spark-skill
Use when reading from or writing to Neo4j with Apache Spark or Databricks using the Neo4j Connector for Apache Spark 6.0 (org.neo4j.connectors:spark) or 5.x (org.neo4j:neo4j-connector-apache-spark). Covers SparkSession setup, DataFrame reads via labels/Cypher/relationship scan, DataFrame writes with
By neo4j-contrib · 501 installs
npx skills add neo4j-contrib/neo4j-skills --skill neo4j-spark-skill
Source repository · Upstream listing
Neo4j Connector for Apache Spark
When to Use
Reading Neo4j nodes/relationships into Spark DataFrames
Writing Spark DataFrames to Neo4j as nodes or relationships
Databricks notebooks connecting to Neo4j
Delta Lake → Neo4j ingestion pipelines
Partitioned parallel reads from large Neo4j graphs
When NOT to Use
Python bolt driver / execute query → neo4j driver python skill
Cypher query writing → neo4j cypher skill
GDS graph algorithms → neo4j gds skill
Spring Boot + Neo4j → neo4j spring data skill
Version Matrix
Connector Spark Scala Java Databricks Runtime Neo4j Maven coordinate
6.0.x 4.0, 4.1 2.13 17+ 17.3 LTS 5.x, 2025.x, 2026.x org.neo4j.connectors:spark:6.0.0 s 2.13
5.5.x / 5.4.x 3.4, 3.5 2.12, 2.13 8+ 14.3–16.4 LTS 4.4, 5.x, 2025.x, 2026.x org.neo4j:neo4j connector apache spark 2.13:5.5.0 for spark 3
Group ID changed in 6.0 — org.neo4j:neo4j connector apache spark <scala is now a relocation POM pointing at org.neo4j.connectors:spark . On Spark 3.x stay on 5.5.x.
6.0 breaking changes
Change Migration
Spark baseline 3.5 → 4.0/4.1; Scala 2.12 and Java 8–11 dropped Upgrade to 5.5.0 first, then Spark 4.x + Scala 2.13 + Java 17
Maven coordinate org.neo4j.connectors:spark:<version s 2.13 Replace old for spark 3 coordinate
schema.optimization.type removed schema.optimization.node.keys , schema.optimization.relationship.keys , schema.optimization
$stream.offset in partitioned reads removed Use partitions + query.count
; separated multi statement script removed script.1 , script.2 , … script.N — executed in numbered order
relationship.save.strategy default native → keys Set .option("relationship.save.strategy", "native") explicitly to keep old behaviour
query option rewritten for Data Source V2 predicate push down No action; verify plans on upgrade
Setup
Standalone Spark (PySpark)
Standalone Spark (Scala)
Databricks — Cluster Installation
1. Cluster → Libraries → Install New → Maven
2. Coordinate org.neo4j.connectors:spark:6.0.0 s 2.13 on DBR 17.3 LTS; org.neo4j:neo4j connector apache spark 2.13:5.5.0 for spark 3 on DBR 14.3–16.4 LTS
3. Cluster → Advanced Options → Spark tab — add config:
4. Use Single user access mode (Unity Catalog shared mode not supported)
Databricks — Secrets (preferred over plaintext)
Key Configuration Options
Option Description Default
neo4j.url Bolt/Neo4j URI — (required)
neo4j.authentication.type none , basic , kerberos , bearer basic
neo4j.authentication.basic.username Username driver default
neo4j.authentication.basic.password Password driver default
neo4j.authentication.bearer.token Bearer token —
neo4j.database Target database driver default
neo4j.access.mode read or write read
neo4j.encryption.enabled TLS (ignored with +s / +ssc URI) false
neo4j.db.transaction.timeout Transaction timeout (ms) driver default
neo4j.db.transaction.metadata.<key Custom transaction metadata surfaced in query log [6.0] empty
neo4j.authentication.type = supplier name Custom AuthenticationTokenSupplierFactory (e.g. keycloak via org.neo4j.connectors:commons authn keycloak ) for expiring OAuth/OIDC tokens —
Cypher version and query tuning [6.0]
Option Effect
cypher.version Cypher language version — 5 (default) or 25
cypher.tuning.<param Emits CYPHER <param =<value preamble on every generated query
Valid with labels , relationship , query on reads and writes; rejected with gds .
Reading from Neo4j
Three mutually exclusive read modes — use exactly one per .read() call.
Label scan (nodes)
Multi label filter (AND): .option("labels", ":Person:Employee")
Result includes <id (internal Neo4j id) and <labels columns.
Cypher query read
Use explicit RETURN aliases — they become DataFrame column names. No SKIP / LIMIT in query (connector handles pagination).
Relationship scan
Result columns: <rel.id , <rel.type , <source. , <target. , plus relationship properties.
Read partition tuning
Full read options reference: [references/read patterns.md](references/read patterns.md)
Writing to Neo4j
SaveMode
SaveMode Cypher Requires
Append CREATE nothing extra
Overwrite MERGE node.keys (nodes) or .node.keys (rels)
ErrorIfExists CREATE + error if exists —
Always create uniqueness constraints on node.keys properties before writing in Overwrite mode.
Write nodes — Append (CREATE)
Write nodes — Overwrite (MERGE)
node.keys with rename: .option("node.keys", "df col:node property,id:personId")
Write nodes — Scala
Write relationships
Use coalesce(1) before relationship writes to avoid deadlocks.
relationship.source.save.mode / relationship.target.save.mode :
Match — find existing nodes (fail if missing)
Append — always CREATE new nodes
Overwrite — MERGE nodes
Pre write scripts [6.0]
script.N runs Cypher once before write operations, in numbered order. Required for index/constraint setup when using query mode ( schema.optimization. rejected there).
script (single statement) and script.N are mutually exclusive. Semicolon separated statements inside one script fail on 6.0.
Full write options reference: [references/write patterns.md](references/write patterns.md)
Databricks — Delta Lake → Neo4j Pipeline
Pipeline pattern for relationships — load both node sets first, then write edges:
Write Performance Tuning
Scenario Recommendation
Node writes (no lock contention) repartition(N) where N ≤ Neo4j CPU cores
Relationship writes (lock risk) coalesce(1) — single partition
Large datasets batch.size 10000–20000 (adjust to heap)
MERGE heavy loads Add uniqueness constraint on node.keys properties first
Common Errors
Error Cause Fix
ClassNotFoundException: org.neo4j.spark.DataSource JAR not on classpath Add spark.jars.packages or attach library
Deadlock on relationship write Multiple partitions locking nodes coalesce(1) before write
Duplicate nodes on Overwrite No uniqueness constraint on keys CREATE CONSTRAINT ON (n:Label) ASSERT n.prop IS UNIQUE
OOM on Neo4j side batch.size too large Reduce to 5000–10000; check heap
Schema all string columns No APOC, schema not sampled Set schema.flatten.limit higher; or use query mode with explicit types
Access mode is read error on write Session opened in read mode Remove neo4j.access.mode or set to write
Databricks Shared cluster fails Unity Catalog shared mode unsupported Switch to Single User access mode
NoSuchMethodError / IncompatibleClassChangeError on Spark 4 5.x connector on a Spark 4 runtime Use org.neo4j.connectors:spark:6.0.0 s 2.13
Relationship write ignores rel. / source. columns after upgrade 6.0 default strategy is keys , not native .option("relationship.save.strategy", "native")
script option rejected with multiple statements 6.0 removed ; separated scripts Split into script.1 , script.2 , …
Checklist
[ ] Connector coordinate matches Spark line — org.neo4j.connectors:spark: s 2.13 for Spark 4.x, org.neo4j:neo4j connector apache spark <scala : for spark 3 for Spark 3.x
[ ] Scala version in artifact matches cluster runtime (2.13 only on 6.x)
[ ] Credentials in Databricks secrets or env vars — not hardcoded
[ ] node.keys set when using Overwrite mode
[ ] Uniqueness constraint created on node.keys properties before MERGE writes
[ ] coalesce(1) applied before relationship writes
[ ] batch.size sized to Neo4j heap (start 5000, tune up)
[ ] Delta Lake → Neo4j: nodes written before relationships
[ ] query mode: no SKIP / LIMIT in Cypher (connector paginates internally)
[ ] Databricks: Single User access mode (not Shared)