plugins/developer-kit-java/skills/spring-data-neo4j/SKILL.md
Provides Spring Data Neo4j integration patterns for Spring Boot applications. Use when you need to work with a graph database, Neo4j nodes and relationships, Cypher queries, or Spring Data Neo4j. Creates node entities with @Node annotation, defines relationships with @Relationship, writes Cypher queries using @Query, configures imperative and reactive Neo4j repositories, implements graph traversal patterns, and sets up testing with embedded databases.
npx skillsauth add giuseppe-trisciuoglio/developer-kit spring-data-neo4jInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Provides Spring Data Neo4j integration patterns for Spring Boot applications. Covers node entity mapping with @Node and @Relationship, repository configuration (imperative and reactive), custom Cypher queries with @Query, and integration testing with embedded Neo4j databases.
Use this skill when working with:
Add the dependency:
Maven:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-neo4j</artifactId>
</dependency>
Gradle:
implementation 'org.springframework.boot:spring-boot-starter-data-neo4j'
Configure connection in application.properties:
spring.neo4j.uri=bolt://localhost:7687
spring.neo4j.authentication.username=neo4j
spring.neo4j.authentication.password=secret
Configure Cypher-DSL dialect (recommended):
@Configuration
public class Neo4jConfig {
@Bean
Configuration cypherDslConfiguration() {
return Configuration.newConfig()
.withDialect(Dialect.NEO4J_5).build();
}
}
Validation Checkpoint: Run
MATCH (n) RETURN count(n)via cypher-shell to verify the connection works before proceeding.
@Node annotation to mark entity classes@Id (immutable, natural identifier)@Id @GeneratedValue (Neo4j internal ID)@Relationship annotation@Property for custom property namesValidation Checkpoint: If entity save fails, check for constraint violations—duplicate IDs violate uniqueness constraints.
Neo4jRepository<Entity, ID> for imperative operationsReactiveNeo4jRepository<Entity, ID> for reactive operations@Query annotation for complex Cypher queries$paramName syntax for parametersValidation Checkpoint: Test repository with
findAll()first—if empty, verify the Neo4j instance is running and credentials are correct.
@DataNeo4jTest for repository testing with test slicingwithFixture() Cypher queriesValidation Checkpoint: If tests fail with "Connection refused", ensure the embedded Neo4j started successfully in
@BeforeAll.
@Node("Movie")
public class MovieEntity {
@Id
private final String title; // Business key as ID
@Property("tagline")
private final String description;
private final Integer year;
@Relationship(type = "ACTED_IN", direction = Direction.INCOMING)
private List<Roles> actorsAndRoles = new ArrayList<>();
@Relationship(type = "DIRECTED", direction = Direction.INCOMING)
private List<PersonEntity> directors = new ArrayList<>();
public MovieEntity(String title, String description, Integer year) {
this.title = title;
this.description = description;
this.year = year;
}
}
@Node("Movie")
public class MovieEntity {
@Id @GeneratedValue
private Long id;
private final String title;
@Property("tagline")
private final String description;
public MovieEntity(String title, String description) {
this.id = null; // Never set manually
this.title = title;
this.description = description;
}
// Wither method for immutability with generated IDs
public MovieEntity withId(Long id) {
if (this.id != null && this.id.equals(id)) {
return this;
} else {
MovieEntity newObject = new MovieEntity(this.title, this.description);
newObject.id = id;
return newObject;
}
}
}
@Repository
public interface MovieRepository extends Neo4jRepository<MovieEntity, String> {
// Query derivation from method name
MovieEntity findOneByTitle(String title);
List<MovieEntity> findAllByYear(Integer year);
List<MovieEntity> findByYearBetween(Integer startYear, Integer endYear);
}
@Repository
public interface MovieRepository extends ReactiveNeo4jRepository<MovieEntity, String> {
Mono<MovieEntity> findOneByTitle(String title);
Flux<MovieEntity> findAllByYear(Integer year);
}
Imperative vs Reactive:
Neo4jRepository for blocking, imperative operationsReactiveNeo4jRepository for non-blocking, reactive operations@Query@Repository
public interface AuthorRepository extends Neo4jRepository<Author, Long> {
@Query("MATCH (b:Book)-[:WRITTEN_BY]->(a:Author) " +
"WHERE a.name = $name AND b.year > $year " +
"RETURN b")
List<Book> findBooksAfterYear(@Param("name") String name,
@Param("year") Integer year);
@Query("MATCH (b:Book)-[:WRITTEN_BY]->(a:Author) " +
"WHERE a.name = $name " +
"RETURN b ORDER BY b.year DESC")
List<Book> findBooksByAuthorOrderByYearDesc(@Param("name") String name);
}
Custom Query Best Practices:
$parameterName for parameter placeholders@Param annotation when parameter name differs from method parameterTest Configuration:
@DataNeo4jTest
class BookRepositoryIntegrationTest {
private static Neo4j embeddedServer;
@BeforeAll
static void initializeNeo4j() {
embeddedServer = Neo4jBuilders.newInProcessBuilder()
.withDisabledServer() // No HTTP access needed
.withFixture(
"CREATE (b:Book {isbn: '978-0547928210', " +
"name: 'The Fellowship of the Ring', year: 1954})" +
"-[:WRITTEN_BY]->(a:Author {id: 1, name: 'J. R. R. Tolkien'}) " +
"CREATE (b2:Book {isbn: '978-0547928203', " +
"name: 'The Two Towers', year: 1956})" +
"-[:WRITTEN_BY]->(a)"
)
.build();
}
@AfterAll
static void stopNeo4j() {
embeddedServer.close();
}
@DynamicPropertySource
static void neo4jProperties(DynamicPropertyRegistry registry) {
registry.add("spring.neo4j.uri", embeddedServer::boltURI);
registry.add("spring.neo4j.authentication.username", () -> "neo4j");
registry.add("spring.neo4j.authentication.password", () -> "null");
}
@Autowired
private BookRepository bookRepository;
@Test
void givenBookExists_whenFindOneByTitle_thenBookIsReturned() {
Book book = bookRepository.findOneByTitle("The Fellowship of the Ring");
assertThat(book.getIsbn()).isEqualTo("978-0547928210");
}
}
Input:
MovieEntity movie = new MovieEntity("The Matrix", "Welcome to the Real World", 1999);
movieRepository.save(movie);
MovieEntity found = movieRepository.findOneByTitle("The Matrix");
Output:
MovieEntity{
title="The Matrix",
description="Welcome to the Real World",
year=1999,
actorsAndRoles=[],
directors=[]
}
Input:
List<Book> books = authorRepository.findBooksAfterYear("J.R.R. Tolkien", 1950);
Output:
[
Book{isbn="978-0547928210", name="The Fellowship of the Ring", year=1954},
Book{isbn="978-0547928203", name="The Two Towers", year=1956},
Book{isbn="978-0547928227", name="The Return of the King", year=1957}
]
Input:
@Query("MATCH (m:Movie)<-[:ACTED_IN]-(a:Person) " +
"WHERE m.title = $title RETURN a.name as actorName")
List<String> findActorsByMovieTitle(@Param("title") String title);
List<String> actors = movieRepository.findActorsByMovieTitle("The Matrix");
Output:
["Keanu Reeves", "Laurence Fishburne", "Carrie-Anne Moss", "Hugo Weaving"]
Progress from basic to advanced examples covering complete movie database, social network patterns, e-commerce product catalogs, custom queries, and reactive operations.
See examples for comprehensive code examples.
@Id) or generated IDs (@Id @GeneratedValue)Neo4jRepository for imperative or ReactiveNeo4jRepository for reactive@Query for complex graph patternswithFixture() Cypher queries@DataNeo4jTest for test slicing@Transactional is properly configured.| Problem | Cause | Solution |
|---------|-------|----------|
| Connection refused on localhost:7687 | Neo4j server not running | Start Neo4j or use embedded Neo4j for tests |
| Authentication failed | Wrong credentials | Check spring.neo4j.authentication.username/password |
| Entity not saved / MATCH returns nothing | Transaction not committed | Add @Transactional or verify auto-commit settings |
| ConstraintViolationException on save | Duplicate @Id value | Ensure IDs are unique or use @GeneratedValue |
| Relationships missing in results | Wrong @Relationship direction | Check Direction.INCOMING/OUTGOING/UNDIRECTED |
| @Query returns wrong data | Cypher parameter syntax | Use $paramName not $ {paramName} |
| Test fails with @DataNeo4jTest | Embedded Neo4j not started | Ensure @BeforeAll starts Neo4j before tests |
For detailed documentation including complete API reference, Cypher query patterns, and configuration options:
development
Provides final code cleanup after task review approval. Removes debug logs, temporary comments, dead code, optimizes imports, and improves readability. Use when asked to clean up code, polish, finalize, tidy up, remove technical debt, or prepare code for completion after review. Not for refactoring logic or fixing bugs—focused solely on cosmetic and hygiene cleanup.
tools
Ralph Wiggum-inspired automation loop for specification-driven development. Orchestrates task implementation, review, cleanup, and synchronization using a Python script. Use when: user runs /loop command, user asks to automate task implementation, user wants to iterate through spec tasks step-by-step, or user wants to run development workflow automation with context window management. One step per invocation. State machine: init → choose_task → implementation → review → fix → cleanup → sync → update_done. Supports --from-task and --to-task for task range filtering. State persisted in fix_plan.json.
testing
Creates, updates, validates, and displays the architectural DNA of a project through two shared documents: docs/specs/architecture.md (technology stack, architectural rules, security constraints, AI guardrails) and docs/specs/ontology.md (domain glossary / Ubiquitous Language). Use BEFORE brainstorm as a project setup step, or at any point in the SDD lifecycle to validate specs/tasks against architecture principles. Triggers on 'create constitution', 'update constitution', 'constitution check', 'validate against constitution', 'project principles', 'architectural guardrails', 'setup project architecture', 'define ontology'.
tools
Provides Qwen Coder CLI delegation workflows for coding tasks using Qwen2.5-Coder and QwQ models, including English prompt formulation, execution flags, and safe result handling. Use when the user explicitly asks to use Qwen for tasks such as code generation, refactoring, debugging, or architectural analysis. Triggers on "use qwen", "use qwen coder", "delegate to qwen", "ask qwen", "second opinion from qwen", "qwen opinion", "continue with qwen", "qwen session".