Bluetape4k Graph Part 1: Database Selection Map

The earlier post When should we adopt GraphDB? answered the first question: use a graph database when relationships are the workload. This series starts at the next problem, the one that tends to last longer in real projects: once graph is the right shape, do we start with Neo4j, measure Memgraph, keep PostgreSQL with AGE, or run tests on something lighter?
bluetape4k-graph does not reimplement graph databases. It keeps Neo4j, Memgraph, Apache AGE, TinkerGraph, and
FalkorDB in their own strengths and gives Kotlin/JVM services a common place for the repetitive work: CRUD wrappers,
batch writes, traversal helpers, bulk I/O, and framework integration. Rebuilding a graph database would be a very
creative way to accidentally start a small database company. That is not the goal here.

| Graph DB | API shape | Good fit |
|---|---|---|
| Neo4j | Cypher over the Neo4j Java Driver | Default production choice when maturity matters |
| Memgraph | Neo4j-compatible Cypher protocol | Low-latency and write-heavy candidates |
| Apache AGE | Cypher-over-SQL on PostgreSQL | PostgreSQL-centered operations |
| TinkerGraph | In-memory TinkerPop/Gremlin | Unit tests, examples, local fixtures |
| FalkorDB | Redis module with openCypher subset | Redis-aligned lightweight graph services |
The table is not trying to crown a single winner. Tests can start with TinkerGraph, production candidates can be measured with Neo4j or Memgraph, AGE can make sense in PostgreSQL-centered operations, and FalkorDB is worth checking when Redis is already the operational center. For edge-heavy writes, measure first. Benchmarks are very good at humbling architecture opinions.
Cypher in one paragraph
Section titled “Cypher in one paragraph”Cypher is a graph query language. SQL asks questions through tables and rows; Cypher asks by drawing a relationship
pattern. The following query starts at a Person, follows a KNOWS edge, and returns connected people.
MATCH (alice:Person {email: $email})-[:KNOWS]->(friend:Person)RETURN friend.nameThe common GraphOperations API does not replace Cypher. Trying to do that would mostly produce a worse Cypher with a
friendlier Kotlin wrapper. GraphOperations gives service code a portable starting point for CRUD, batch writes,
traversal, and tests. When a production query needs planner control, projections, or storage-specific tuning, use the
native Cypher path offered by Neo4j, Memgraph, Apache AGE, or FalkorDB.

graph-core sits in the middle; graph storage adapters, graph I/O, Spring Boot, and Ktor compose around it.The common API is useful, but it should not erase graph storage semantics. Query planners, indexes, traversal behavior, and transaction semantics differ enough that a quiet no-op is worse than an early failure. Start with TinkerGraph for fast tests, then measure Neo4j, Memgraph, AGE, or FalkorDB with the workload you actually have.
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))My default split is simple: Neo4j for production, TinkerGraph for tests. Add Memgraph when low-latency writes matter, AGE when PostgreSQL consolidation matters, and FalkorDB when Redis is already the operational center.
Sources
Section titled “Sources”Series
Section titled “Series”- Part 1: Database Selection Map
- Part 2: Core API and Execution Models
- Part 3: Graph I/O and Benchmarks
- Part 4: Workshop Scenarios and Service Integration
- Part 5: Reading the Virtual Threads Benchmark
Comments
Leave a note or reaction with your GitHub account.