Graphite is a Java-first graph access library designed for developers who use Neo4j in modern applications and want a more expressive, type-safe, maintainable way to work with graph data.
Graphite does not try to replace graphs with relational thinking. It embraces graph modelling, traversal, relationships, and pattern matching — while removing unnecessary friction from day-to-day Java development.
Many Java developers using Neo4j eventually fall into one of these paths:
- Writing raw Cypher strings across the codebase
- Manually managing
MATCH,MERGE, aliases, and parameters - Mixing persistence logic with business logic
- Losing refactor safety due to string-based queries
- Treating graph access as an escape hatch instead of a first-class model
Cypher is powerful, but raw query strings everywhere do not scale well in large codebases.
A graph database deserves a graph-native programming model.
Java developers should be able to express graph intent in code using fluent, composable, testable APIs — in the same spirit that collections gained power through Streams.
Instead of writing:
MATCH (c:Consultant)-[:REFERRED_BY]->(m:Consultant)
WHERE c.id = $id
RETURN mA developer should be able to express intent like:
graphite
.match(node(Consultant.class).as("c"))
.out(REFERRED_BY)
.to(node(Consultant.class).as("m"))
.where(property("c", "id").eq(id))
.select("m");The concern is no longer syntax. The concern becomes meaning.
Graphite is designed for Java developers first. The API should feel natural in Java, readable in Java, and maintainable in Java.
Graphs are not tables. Relationships are first-class citizens. Traversal matters. Paths matter. Direction matters. Graphite respects that.
Use compile-time guarantees where they create real value:
- projections
- property references
- node metadata
- query structure
Avoid complexity when type safety becomes ceremony.
No abstraction covers 100% of real use cases. Graphite should always allow direct Cypher when needed.
Queries should be assembled from small composable parts. Avoid hidden runtime behaviour, surprising conventions, or excessive annotations.
The heart of Graphite is framework-independent. Spring integration, Boot starters, repositories, and adapters come later. The core model must stand alone.
A query should communicate intent clearly to future maintainers. Readable persistence code is a competitive advantage.
Graphite does not aim to:
- Hide graph concepts behind relational abstractions
- Replace Cypher entirely
- Become a heavy ORM
- Generate accidental complexity through annotations and magic proxies
- Lock users into a proprietary runtime model
Graphite is structured carbon. Strong, elegant, layered, and useful. It evokes writing, modelling, and precision. A fitting metaphor for expressing graph systems cleanly.
Graphite should become the most natural way to use graph databases from Java:
- expressive queries
- clean architecture
- testable graph access
- framework integrations
- strong developer experience
- modern language design
Databases should serve software design. Software design should not be distorted by database syntax.
Graphite exists to restore that balance.
- JDK 21+
- Maven 3.8.7+
graphite-bom: published dependency-management BOMgraphite-core: core graph API primitivesgraphite-cypher: Cypher-oriented query building utilitiesgraphite-metadata: metadata and mapping modelsgraphite-spring: Spring integration layergraphite-spring-boot-starter: starter entrypoint modulegraphite-test: shared test support utilitiesgraphite-examples: minimal usage examples
io.github.riken127.graphite.core.dsl: fluent API entry points and buildersio.github.riken127.graphite.core.model: immutable query ASTio.github.riken127.graphite.core.model.predicate: predicate model typesio.github.riken127.graphite.core.validation: query validation rules
io.github.riken127.graphite.cypher.renderer: query renderers and helpersio.github.riken127.graphite.cypher.model: rendered Cypher output model
.editorconfigdefines shared editor defaultsspotless-maven-pluginenforces Google Java format and normalized POM/markdown formattingmaven-checkstyle-pluginenforcesgoogle_checks.xml
# format Java + POM + markdown files
mvn spotless:apply
# run compile, tests, style, and lint checks
mvn verify
# run tests for one module
mvn -pl graphite-core testMatchQuery query =
Graphite.match(Graphite.node("Consultant").as("c"))
.where(Graphite.property("c", "id").eq("123"))
.where(Graphite.property("c", "skills").in(List.of("java", "neo4j")))
.where(Graphite.property("c", "deletedAt").isNull())
.select("c", "c.id")
.orderBy(Graphite.desc("c", "createdAt"))
.skip(0)
.limit(25)
.build();
RenderedQuery rendered = new MatchQueryRenderer().render(query);CreateQuery createQuery =
Graphite.create(Graphite.node("Consultant").as("c"))
.set("id", "123")
.set("name", "Julia")
.build();
MergeQuery mergeQuery =
Graphite.merge(Graphite.node("Consultant").as("c"))
.on("id", "123")
.on("tenant", "acme")
.onCreateSet("createdAt", "2026-04-20")
.onMatchSet("lastSeen", "2026-04-20")
.build();