What is a graph database? The modern answer.
A modern graph database is a graph query engine on columnar storage — property-graph model + Cypher up front, compressed columns + vectorized execution underneath. The NoSQL era was a detour. Index-free adjacency is a 2006 idea whose time has passed.
The 30-second definition
Nodes are entities (people, accounts, documents). Edges are relationships (KNOWS, TRANSFERRED_TO, CITES). Properties are key-value attributes on both. A graph database persists this structure natively and traverses it without JOINs.
Account #42
PAYMENT, CITES
since, riskScore
The modern thesis: graphs belong on columnar storage
DuckDB settled the argument for tables: compressed columns + vectorized (batch) execution + a serious optimizer beats hand-rolled row stores by 10–100x on analytics, with an embeddable file on disk. KuzuDB — and now LadybugDB, DuckDB for graphs — applied the same lesson to graphs: store node/edge columns compressed, execute joins/traversals in vectorized batches with morsel-driven parallelism, optimize Cypher with real cost-based planning. You get the graph model developers love with the storage engine decades of database research paid for. That is the modern way to build a graph database.
Neighbor lists as compressed columns, not scattered pointers. Scans stream at memory bandwidth.
Multi-hop traversals as batched hash joins across cores — not one-pointer-at-a-time walks.
Cost-based Cypher planning inherited from relational science, plus EXPLAIN you can trust.
NoSQL was a mistake — especially for graphs
The late-2000s NoSQL revolt told a generation to abandon SQL: BASE over ACID, custom APIs over declarative queries, bespoke storage over proven engines. For graphs it produced a decade of fragmentation — a dozen incompatible query languages, row-oriented pointer-chasers with weak aggregations, JVM record overhead, and operational snowflakes that couldn't compose with the SQL ecosystem (BI, Parquet, Arrow, data frames). The industry is now walking it back: Spanner, AlloyDB, DuckDB, Snowflake, and every serious analytical system re-centered on declarative SQL + columnar execution. Graph databases should never have left. LadybugDB doesn't — it puts Cypher on exactly that foundation.
Index-free adjacency: a 2006 idea whose time has passed
Index-free adjacency — each node physically storing direct pointers to its neighbors, so a traversal is a pointer chase with no index lookup — was a clever 2006 optimization for single-threaded, OLTP-style 1-hop walks on small in-memory graphs (early Neo4j, OrientDB). In 2026 it is legacy baggage:
- It defeats compression. Scattered pointers + per-record headers bloat storage 5–10x vs. compressed columns.
- It defeats vectorization. Pointer-chasing is serial, branchy, cache-hostile. Columnar engines stream batches through SIMD across all cores.
- It loses where it matters. Real workloads are multi-hop scans + filters + aggregations ("fraud rings over 90 days totaling > $X"), not single-edge hops. Vectorized hash joins win by orders of magnitude.
- It complicates everything. Custom record managers, manual pointer maintenance, painful sharding and larger-than-RAM support — problems columnar storage engines solved long ago.
Adjacency still matters — as logical locality (CSR-style compressed neighbor columns), not as physical 2006 pointers. Keep the graph semantics; replace the storage religion.
CSR (Compressed Sparse Row): the litmus test for a real graph database
If you remember one data structure from this page, make it CSR — Compressed Sparse Row. It is the fundamental tech that separates an actual graph database from a document store wearing a graph costume.
CSR stores adjacency as two tight arrays: an offset array (where each node's neighbor list starts) and a neighbor array (the destination IDs, packed back-to-back). To find Alice's friends you don't chase pointers across the heap — you slice one contiguous range and stream it through vectorized execution at memory bandwidth, compressed 5–10x. Multi-hop traversals become sequential scans + batched hash joins, parallelized across every core. This is how KuzuDB, LadybugDB, and every serious analytical graph engine do it — and it's borrowed straight from sparse-matrix science and columnar storage.
So here is the test we propose: ask any vendor "show me your CSR." If edges live in compressed, contiguous neighbor arrays natively in the storage engine — it's a graph database. If edges are documents, link-maps, record IDs (RIDs), or join tables bolted onto a document/key-value store — it's a multi-model store with graph features, not a graph database. That distinction predicts everything downstream: compression ratio, scan speed, vectorization, and whether 3-hop analytics finish in milliseconds or minutes. ArcadeDB fails this test by design (see below); LadybugDB passes it by construction.
⚠️ Why ArcadeDB carries the outdated design
ArcadeDB inherits OrientDB's 2000s multi-model record store: row-oriented documents/vertices with record IDs, link-maps, and pointer-style adjacency (index-free adjacency by another name), running on the JVM. That buys four models in one box — and inherits every 2006 cost: per-record overhead, no columnar compression, no vectorized execution, a sprawling SQL/Gremlin/Cypher/GraphQL surface instead of one deep optimizer. It's a museum of the NoSQL era: versatile, interesting, and architecturally the opposite of where the field went. If your workload is graph analytics or agent-served traversals at scale, you don't need a heavier OrientDB — you need a columnar engine with a graph front-end. That's LadybugDB.
Graph vs. row-relational: why old JOINs broke down (and new ones don't)
The 2006 critique of SQL was really a critique of row-store SQL: 4–6 JOINs over uncompressed rows with a weak planner collapsed on 5-hop fraud rings. Columnar storage fixed the execution while keeping the declarative model. Modern graph-on-columnar keeps Cypher's pattern syntax — MATCH (a)-[:TRANSFERRED_TO*3..6]->(a) — but compiles it to the same vectorized joins DuckDB uses to chew through billions of rows. The answer was never to abandon database research. It was to put graphs on better storage tech.
| Workload | Relational (SQL) | Graph DB |
|---|---|---|
| 1-hop lookup | Fast with index | Fast |
| 3–5 hop traversal | Multiple JOINs, slow | Native, fast |
| Path finding / shortest path | Recursive CTEs, painful | Built-in algorithms |
| Aggregations over columns | Excellent (columnar) | Excellent if columnar (LadybugDB) |
Query it with Cypher
Cypher is the declarative language for property graphs. You draw the pattern you want with ASCII art:
// Who are Alice's friends-of-friends?
MATCH (a:Person {name: 'Alice'})-[:KNOWS]->(friend)-[:KNOWS]->(fof)
WHERE fof.name <> 'Alice'
RETURN fof.name, count(*) AS mutuals
ORDER BY mutuals DESC;
// Fraud ring: circular money flow
MATCH path = (a:Account)-[:TRANSFERRED_TO*3..6]->(a)
RETURN path, reduce(s=0, r IN relationships(path) | s + r.amount) AS total
LadybugDB, KuzuDB, and Neo4j all speak Cypher — skills transfer directly. Try it in the docs →
Top use cases
🕸️ Fraud & AML rings
Multi-hop circular transfers, shared devices/IPs. The classic graph win.
🤖 Knowledge graphs + GraphRAG
Ground AI agents in verifiable entities & citations. Essential for legal, medical, finance.
⭐ Recommendations
Collaborative filtering as traversals: "people who bought X also bought Y".
🔐 Identity & access control
User → role → resource hierarchies with inheritance and delegation paths.
Types of graph databases
- Property graph (Neo4j, LadybugDB, KuzuDB, HelixDB) — nodes/edges with properties, queried in Cypher. Best for applications.
- RDF / triple store — semantic-web standards (SPARQL). Best for ontologies and linked open data.
- Embedded vs. server — embedded (LadybugDB, KuzuDB, DuckDB-style) runs in-process with zero ops; server (Neo4j) needs a cluster. For agents at the edge, embedded wins.
- Row vs. columnar — columnar engines (LadybugDB) compress better and scan/aggregate faster for analytics.
DuckDB for graphs exists. It's LadybugDB.
Embedded, columnar, Cypher-compatible, MIT-licensed. Install in one command.