Skip to content

Bluetape4k Graph Part 1: Graph Database Selection Criteria

A robotic engineer comparing Neo4j, Memgraph, AGE, TinkerGraph, and FalkorDB graph database blocks on a 3D workbench
Choose a graph database by workload and operating constraints, not preference.

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.

Criteria for selecting Neo4j, Memgraph, Apache AGE, TinkerGraph, or FalkorDB by workload and operating constraints
Separate test strategy, operating environment, and read and write characteristics before choosing a graph database.

The project currently supports the following graph stores.

Graph databaseQuery modelBest fit
Neo4jCypher through the Neo4j Java DriverProduction graph services that need mature tooling, indexes, and transaction support
MemgraphCypher through a Neo4j-compatible protocolCandidate for latency-sensitive Cypher workloads
Apache AGECypher-over-SQL through PostgreSQL/JDBCPostgreSQL-centered deployments that do not want a separate graph server
TinkerGraphIn-memory JVM TinkerPop/GremlinUnit and integration tests, examples, and local demos
FalkorDBAn openCypher subset over a Redis moduleRedis-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.

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.name

This 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 with graph-core surrounded by storage adapters, graph I/O, Spring Boot and Ktor integration, and executable examples
Storage adapters, bulk I/O, and framework integration compose around the common contracts in graph-core.
ModuleResponsibility
graph-coreCommon contracts for GraphOperations, schema DSL, traversal, algorithms, and optional merge and transaction capabilities
graph-age, graph-neo4j, graph-memgraph, graph-tinkerpop, graph-falkordbStore-specific implementations
graph-io/*CSV, NDJSON, and GraphML bulk I/O plus OkIO streaming, compression, and encryption composition
spring-boot/graph-spring-bootSpring Boot 4 auto-configuration
ktor/graph-ktorKtor 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.

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.

The following order is a practical way to build an initial candidate list.

ConstraintFirst candidateAdditional validation
Mature graph-specific operations and Cypher supportNeo4jQuery plans, indexes, and operating cost
Latency-sensitive Cypher workloadMemgraphBenchmarks with actual data and write patterns
PostgreSQL-centered operationsApache AGECypher-over-SQL constraints and PostgreSQL resource contention
Tests and examples without an external serverTinkerGraphBackend-specific integration tests for semantic differences
Redis-backed graph serviceFalkorDBopenCypher 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.