Bluetape4k Graph Part 1: Graph Database Selection Criteria

The earlier post When should we adopt GraphDB? established the first criterion: consider a graph database when relationships are central to the workload. This article addresses the next decision. It explains how to choose between Neo4j and Memgraph as production candidates, when Apache AGE fits a PostgreSQL-centered environment, and which store to use for tests.
bluetape4k-graph does not reimplement graph databases. It retains the storage engines and query languages of Neo4j,
Memgraph, Apache AGE, TinkerGraph, and FalkorDB, while defining common contracts for repetitive Kotlin/JVM service work:
vertex and edge CRUD, batch writes, traversal, bulk I/O, and framework integration.

Supported graph databases
Section titled “Supported graph databases”The project currently supports the following graph stores.
| Graph database | Query model | Best fit |
|---|---|---|
| Neo4j | Cypher through the Neo4j Java Driver | Production graph services that need mature tooling, indexes, and transaction support |
| Memgraph | Cypher through a Neo4j-compatible protocol | Candidate for latency-sensitive Cypher workloads |
| Apache AGE | Cypher-over-SQL through PostgreSQL/JDBC | PostgreSQL-centered deployments that do not want a separate graph server |
| TinkerGraph | In-memory JVM TinkerPop/Gremlin | Unit and integration tests, examples, and local demos |
| FalkorDB | An openCypher subset over a Redis module | Redis-backed graph workloads and lightweight graph services |
This table is not a product ranking. It is a starting point for selecting candidates that fit the operating environment and actual workload. For example, a team that standardizes on PostgreSQL can use Apache AGE to avoid adding a separate graph server. FalkorDB becomes a candidate when the service must fit a Redis-centered operating model. Claims about Memgraph latency or any store’s write performance still need measurements with the application’s data scale and query patterns.
TinkerGraph starts quickly without an external server, which makes it suitable for tests. However, passing a common contract test on TinkerGraph does not prove that Neo4j, Memgraph, Apache AGE, and FalkorDB have the same query planner, index behavior, or transaction semantics. Revalidate each production candidate with backend-specific integration tests, including its Testcontainers environment.
What is Cypher?
Section titled “What is Cypher?”Cypher appears when evaluating Neo4j, Memgraph, Apache AGE, and FalkorDB. It is a query language for describing graph relationship patterns. SQL queries tables and rows; Cypher describes patterns formed by vertices and edges.
MATCH (alice:Person {email: $email})-[:KNOWS]->(friend:Person)RETURN friend.nameThis query starts at a Person vertex, follows a KNOWS edge, and returns the connected person’s name. Instead of
assembling complex joins and recursive traversal in application code, the query sends the relationship shape to the
database.
The common bluetape4k-graph API does not replace Cypher. Service code can start with GraphOperations for basic CRUD,
batch writes, traversal, and tests. Work that requires store-specific control over query planning, indexes, or
projections should use the selected backend’s driver and native query API. The common API reduces repetitive service
code; it does not make the query semantics of different stores identical.
Module structure
Section titled “Module structure”
graph-core.| Module | Responsibility |
|---|---|
graph-core | Common contracts for GraphOperations, schema DSL, traversal, algorithms, and optional merge and transaction capabilities |
graph-age, graph-neo4j, graph-memgraph, graph-tinkerpop, graph-falkordb | Store-specific implementations |
graph-io/* | CSV, NDJSON, and GraphML bulk I/O plus OkIO streaming, compression, and encryption composition |
spring-boot/graph-spring-boot | Spring Boot 4 auto-configuration |
ktor/graph-ktor | Ktor 3 ApplicationPlugin integration |
examples/* | Executable scenarios for code dependencies, fraud detection, IAM, recommendations, supply chains, and other graph workloads |
GraphOperations combines GraphSession, vertex and edge repositories, traversal, and algorithm repository contracts.
Schema management, merge, and transaction DSLs are optional capabilities implemented by backends that can provide
stronger guarantees. A common interface therefore does not imply that every backend processes every capability in the
same way. Check the backend capability matrix and integration tests for unsupported operations and failure semantics.
A minimal starting point
Section titled “A minimal starting point”Tests and documentation examples can start with TinkerGraph. The following code creates a graph without Docker, adds vertices and an edge, and retrieves neighboring vertices.
val ops: GraphOperations = TinkerGraphOperations()
ops.createGraph("demo")
val alice = ops.createVertex("Person", mapOf("name" to "Alice"))val bob = ops.createVertex("Person", mapOf("name" to "Bob"))ops.createEdge(alice.id, bob.id, "KNOWS", mapOf("since" to 2026))
val neighbors = ops.neighbors(alice.id, NeighborOptions(edgeLabel = "KNOWS"))
ops.close()This example explains the basic GraphOperations contract. It does not prove the production-store decision. Run the
same domain scenario against Neo4j, Memgraph, Apache AGE, and FalkorDB integration tests, then measure query latency and
write throughput at production data scale.
Selection criteria
Section titled “Selection criteria”The following order is a practical way to build an initial candidate list.
| Constraint | First candidate | Additional validation |
|---|---|---|
| Mature graph-specific operations and Cypher support | Neo4j | Query plans, indexes, and operating cost |
| Latency-sensitive Cypher workload | Memgraph | Benchmarks with actual data and write patterns |
| PostgreSQL-centered operations | Apache AGE | Cypher-over-SQL constraints and PostgreSQL resource contention |
| Tests and examples without an external server | TinkerGraph | Backend-specific integration tests for semantic differences |
| Redis-backed graph service | FalkorDB | openCypher subset and actual read and write performance |
If a default pairing is useful, Neo4j can be the first production candidate and TinkerGraph the fast test store. This is not a universal answer. PostgreSQL consolidation, a Redis-centered operating model, or strict latency requirements may put another backend first. Measure the candidate that best matches the dominant constraint.
The next article examines the graph-core API, schema DSL, transaction and merge capabilities, and synchronous,
virtual-thread, and coroutine execution models.
Comments
Leave a note or reaction with your GitHub account.