$npx -y skills add neo4j-contrib/neo4j-skills --skill neo4j-spring-data-skillUse when building Spring Boot applications with Neo4j using Spring Data Neo4j (SDN 7.x/8.x):
| 1 | # Neo4j Spring Data Skill |
| 2 | |
| 3 | ## When to Use |
| 4 | |
| 5 | - Configuring Spring Boot with Neo4j (`spring-boot-starter-data-neo4j`) |
| 6 | - Writing `@Node` entity classes and `@Relationship`/`@RelationshipProperties` mappings |
| 7 | - Defining `Neo4jRepository` or `ReactiveNeo4jRepository` interfaces |
| 8 | - Writing `@Query` annotations with Cypher on repository methods |
| 9 | - Using Spring projections (interface-based, DTO, dynamic) with Neo4j |
| 10 | - Configuring `application.yml` for Neo4j connection |
| 11 | - Custom queries via `Neo4jClient` or `Neo4jTemplate` |
| 12 | - Spring AI `Neo4jVectorStore` for vector search in Spring apps |
| 13 | - Transaction management, auditing, optimistic locking |
| 14 | |
| 15 | ## When NOT to Use |
| 16 | |
| 17 | - **Raw Java driver without Spring** → `neo4j-driver-java-skill` |
| 18 | - **Cypher query authoring** → `neo4j-cypher-skill` |
| 19 | - **Driver version upgrades** → `neo4j-migration-skill` |
| 20 | - **GDS algorithms** → `neo4j-gds-skill` |
| 21 | |
| 22 | --- |
| 23 | |
| 24 | ## Version Matrix |
| 25 | |
| 26 | | SDN | Spring Boot | Spring Framework | Java | Neo4j | |
| 27 | |--------|-------------|-----------------|------|-------| |
| 28 | | 8.0.x | 3.3.x / 3.4.x | 6.2.x | 17+ | 5.15+ | |
| 29 | | 8.1.x | 3.4.x+ | 7.0.x | 17+ | 5.15+ | |
| 30 | | 7.5.x | 3.2.x | 6.1.x | 17+ | 4.4+ | |
| 31 | |
| 32 | Use `spring-boot-starter-data-neo4j` — it pulls SDN + driver. No explicit SDN version needed when using Spring Boot BOM. |
| 33 | |
| 34 | --- |
| 35 | |
| 36 | ## Setup |
| 37 | |
| 38 | ### Maven |
| 39 | |
| 40 | ```xml |
| 41 | <dependency> |
| 42 | <groupId>org.springframework.boot</groupId> |
| 43 | <artifactId>spring-boot-starter-data-neo4j</artifactId> |
| 44 | </dependency> |
| 45 | ``` |
| 46 | |
| 47 | ### Gradle |
| 48 | |
| 49 | ```gradle |
| 50 | implementation 'org.springframework.boot:spring-boot-starter-data-neo4j' |
| 51 | ``` |
| 52 | |
| 53 | ### Reactive stack (add alongside above) |
| 54 | |
| 55 | ```xml |
| 56 | <dependency> |
| 57 | <groupId>org.springframework.boot</groupId> |
| 58 | <artifactId>spring-boot-starter-webflux</artifactId> |
| 59 | </dependency> |
| 60 | ``` |
| 61 | |
| 62 | --- |
| 63 | |
| 64 | ## Configuration |
| 65 | |
| 66 | ### application.yml — imperative (standard) |
| 67 | |
| 68 | ```yaml |
| 69 | spring: |
| 70 | neo4j: |
| 71 | uri: ${NEO4J_URI:bolt://localhost:7687} |
| 72 | authentication: |
| 73 | username: ${NEO4J_USERNAME:neo4j} |
| 74 | password: ${NEO4J_PASSWORD} |
| 75 | data: |
| 76 | neo4j: |
| 77 | database: ${NEO4J_DATABASE:neo4j} |
| 78 | ``` |
| 79 | |
| 80 | ### application.yml — Aura (TLS required) |
| 81 | |
| 82 | ```yaml |
| 83 | spring: |
| 84 | neo4j: |
| 85 | uri: ${NEO4J_URI} # neo4j+s://xxxx.databases.neo4j.io |
| 86 | authentication: |
| 87 | username: ${NEO4J_USERNAME:neo4j} |
| 88 | password: ${NEO4J_PASSWORD} |
| 89 | data: |
| 90 | neo4j: |
| 91 | database: ${NEO4J_DATABASE:neo4j} |
| 92 | ``` |
| 93 | |
| 94 | Credentials: store in `.env`; never hardcode. Verify `.env` is in `.gitignore`. |
| 95 | |
| 96 | --- |
| 97 | |
| 98 | ## Entity Mapping |
| 99 | |
| 100 | ```java |
| 101 | import org.springframework.data.neo4j.core.schema.*; |
| 102 | |
| 103 | // Internal generated ID (default for most cases) |
| 104 | @Node("Person") |
| 105 | public class PersonEntity { |
| 106 | @Id @GeneratedValue private Long id; // element ID (Long) |
| 107 | private String name; |
| 108 | @Property("birth_year") private Integer birthYear; // custom property name |
| 109 | @Relationship(type = "KNOWS", direction = Relationship.Direction.OUTGOING) |
| 110 | private List<PersonEntity> friends = new ArrayList<>(); |
| 111 | } |
| 112 | |
| 113 | // UUID business key |
| 114 | @Node("Product") |
| 115 | public class ProductEntity { |
| 116 | @Id @GeneratedValue(generatorClass = GeneratedValue.UUIDStringGenerator.class) |
| 117 | private String id; |
| 118 | @Version private Long version; // optimistic locking; required with business key |
| 119 | } |
| 120 | |
| 121 | // User-assigned key (caller sets value; no @GeneratedValue) |
| 122 | @Node("Country") |
| 123 | public class CountryEntity { |
| 124 | @Id private String isoCode; |
| 125 | private String name; |
| 126 | } |
| 127 | |
| 128 | // Multiple static labels |
| 129 | @Node(primaryLabel = "Vehicle", labels = {"Car", "Auditable"}) |
| 130 | public class CarEntity { ... } |
| 131 | |
| 132 | // Runtime labels |
| 133 | @Node("Content") |
| 134 | public class ContentEntity { |
| 135 | @Id @GeneratedValue private Long id; |
| 136 | @DynamicLabels private Set<String> tags = new HashSet<>(); // labels added at runtime |
| 137 | } |
| 138 | ``` |
| 139 | |
| 140 | --- |
| 141 | |
| 142 | ## Relationship Properties |
| 143 | |
| 144 | Use `@RelationshipProperties` when the relationship itself carries data. |
| 145 | |
| 146 | ```java |
| 147 | @RelationshipProperties |
| 148 | public class RolesRelationship { |
| 149 | |
| 150 | @RelationshipId // internal relationship ID; required |
| 151 | private Long id; |
| 152 | |
| 153 | private List<String> roles; |
| 154 | |
| 155 | @TargetNode // marks the other end of the relationship |
| 156 | private PersonEntity person; |
| 157 | } |
| 158 | ``` |
| 159 | |
| 160 | ```java |
| 161 | @Node("Movie") |
| 162 | public class MovieEntity { |
| 163 | |
| 164 | @Id @GeneratedValue |
| 165 | private Long id; |
| 166 | |
| 167 | private String title; |
| 168 | |
| 169 | @Relationship(type = "ACTED_IN", direction = Relationship.D |