You are building the simplest thing that could possibly answer one question: "how is this connected to that?" Friends of friends, the parts that make up an assembly, the accounts a fraud ring routes money through, the page that links to the page that links to yours. The shape is always the same — entities joined by relationships — and the query is almost always "walk the relationships and tell me what you reach."
The obvious plan is a relational one: a USER_FRIEND(user, friend) join table. It works beautifully for one hop. But "friends of friends of friends" is the same table self-joined, once per hop, and the intermediate result explodes combinatorially. With a million users averaging 50 friends each, a depth-4 query materializes on the order of 6.25 million candidate rows (depth-5: ~312 million) that the engine must build, sort, and dedupe. In the classic Neo4j in Action benchmark, that depth-4 query ran in ~1.3 s on a graph store while MySQL took ~1,543 s — and could not finish depth 5 at all. The join didn't get slow; it melted.
So you change the storage, not the query. You make edges first-class: every node stores a direct pointer to its own relationship records, so following an edge is a pointer dereference — roughly O(1), and independent of how big the graph is — instead of a B-tree index seek that pays O(log N) on every hop and gets slower as the data grows. That one trick is index-free adjacency, and it is the entire reason this category of database exists. The tagline for the whole course: follow pointers, don't join tables.
The honest other half — which you will build toward and feel directly — is that the same design has no locality for whole-graph work. A k-hop traversal lights up a few nodes; PageRank lights up every node, every pass. Global aggregates have nothing for index-free adjacency to exploit, and you fall back to the Pregel / "think like a vertex" world of supersteps and barriers. Resist the urge to "describe Neo4j." Build the store yourself — the records, the pointer chains, the pattern compiler, the locks, the partition cut — and you will know exactly where a graph database shines and exactly where it stumbles.