I reach for graph data when the relationship is the question. If the business asks who is connected to whom, how risk spreads, or which path links two entities, I recommend modeling edges as first class data.
The path is the data
Graph data is the right shape when the relationship is more important than the row.
How relationships reveal hidden behavior
Graph data is the right shape when the relationship is more important than the row.
Where connected data lives
When I talk about "Where connected data lives", I am checking whether Graph Data Architecture can be traced back, trusted, and used by someone making a decision.
Neo4j, Amazon Neptune, Cosmos DB graph APIs, JanusGraph, TigerGraph, RDF stores, graph tables in lakehouses, Elasticsearch for graph backed search projections.
Managed graph options
| Provider | Typical services |
|---|---|
| AWS | Neptune, Glue, S3, OpenSearch, SageMaker. |
| Azure | Cosmos DB graph APIs, Azure Databricks, AI Search, Synapse. |
| Google Cloud | Cloud Spanner Graph, BigQuery, Dataflow, Vertex AI, partner graph databases. |
Relationship pattern to remember
My recommendation in "Relationship pattern to remember" is to keep the raw source close enough that the answer can be explained later.
Pinterest is a public example: its Taste Graph connects people, pins, topics, and interests so recommendation and advertising systems can reason about relationships rather than isolated rows.
Fraud ring example
I use "Fraud ring example" to keep Graph Data Architecture grounded in a real system, because abstract patterns are too easy to agree with and too hard to operate.
A fraud platform links accounts, cards, devices, addresses, and login IPs. A graph query finds new accounts that share a device with previously blocked accounts within two hops.
Graph review query
I use "Graph review query" to connect the data type to the person, workflow, or system that will consume it.
MATCH (a:Account {id: $accountId})-[:USED_DEVICE]->(d:Device)<-[:USED_DEVICE]-(other:Account)
WHERE other.status = 'BLOCKED'
WITH a, count(distinct other) as blocked_neighbors, collect(d.id) as shared_devices
RETURN a.id,
blocked_neighbors,
shared_devices,
CASE WHEN blocked_neighbors >= 2 THEN 'REVIEW' ELSE 'ALLOW' END as decision;
The query follows shared device relationships, counts blocked neighbors, and returns a review decision. The graph is useful because the risky pattern is in the connection path.
Graph traps to watch
- Define edge direction and meaning carefully.
- Prevent graph traversals from becoming unbounded.
- Keep graph features explainable for reviewers.