neo4j-spring-data-skill
Installation
SKILL.md
Neo4j Spring Data Skill
Status: Draft / WIP — Content is a placeholder. Reference files to be added.
When to Use
- Configuring Spring Boot with Neo4j (
spring-boot-starter-data-neo4j) - Writing
@Nodeentity classes and@Relationshipmappings - Defining
Neo4jRepository/ReactiveNeo4jRepositoryinterfaces - Writing
@Queryannotations with Cypher on repository methods - Using Spring projections (interface-based or DTO-based) with Neo4j
- Configuring
application.ymlfor Neo4j connection - Spring AI
Neo4jVectorStorefor vector search in Spring apps
When NOT to Use
- Raw Java driver without Spring → use
neo4j-driver-java-skill - Cypher query authoring → use
neo4j-cypher-skill - Driver version upgrades → use
neo4j-migration-skill
Setup
pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-neo4j</artifactId>
</dependency>
application.yml:
spring:
neo4j:
uri: ${NEO4J_URI:neo4j+s://host.databases.neo4j.io}
authentication:
username: ${NEO4J_USERNAME:neo4j}
password: ${NEO4J_PASSWORD}
data:
neo4j:
database: ${NEO4J_DATABASE:neo4j}
Core Patterns
Entity mapping
import org.springframework.data.neo4j.core.schema.*;
@Node("Person")
public class Person {
@Id @GeneratedValue private Long id;
private String name;
private String email;
@Relationship(type = "KNOWS", direction = Relationship.Direction.OUTGOING)
private List<Person> friends = new ArrayList<>();
}
Repository
Security:
@Queryannotations MUST use$parameterplaceholders — never string-concatenate user input into Cypher. Spring Data does not sanitize string interpolation; concatenation is a Cypher injection hole.
import org.springframework.data.neo4j.repository.Neo4jRepository;
public interface PersonRepository extends Neo4jRepository<Person, Long> {
Optional<Person> findByName(String name);
// CORRECT: $name is a bound parameter
@Query("MATCH (p:Person {name: $name})-[:KNOWS]->(f) RETURN f")
List<Person> findFriendsOf(String name);
// WRONG: never do this
// @Query("MATCH (p:Person {name: '" + name + "'}) RETURN p") // injection risk
}
Reactive repository
import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository;
import reactor.core.publisher.Flux;
public interface PersonRepository extends ReactiveNeo4jRepository<Person, Long> {
@Query("MATCH (p:Person {name: $name})-[:KNOWS]->(f) RETURN f")
Flux<Person> findFriendsOf(String name);
}
Checklist
-
@Nodeuses a specific label string (not just@Nodewith default class name) -
@Id @GeneratedValueon internal ID field (or@Idon a business key with constraint) -
@Relationshipdirection is explicit (OUTGOING / INCOMING) -
@QueryCypher uses$paramNameparameters (not concatenation) - Database name configured in
application.yml(avoids default DB ambiguity) - Unique constraint in DB for any business key used in repository lookups