Multi Hop Traversal
Introduction
Welcome back to Advanced Queries! We're now at the halfway point in our course, having learned how to aggregate data and match complex patterns in graphs. In this third unit, we're expanding our pattern-matching capabilities by learning how to traverse paths of varying lengths through the graph.
So far, we've worked with fixed-length patterns. When we wanted to find friends of friends, we explicitly wrote two relationship hops in our pattern. But what if we want to find all connections within three degrees of separation, regardless of whether they're one, two, or three hops away? Or what if we need to find all possible paths between two people, no matter how long those paths might be?
This is where variable-length traversals become essential. In this lesson, we'll discover how to write patterns that can match paths of flexible lengths, extract detailed information about the paths we find, and understand the performance implications of traversing deeper into our graph. These techniques are fundamental for analyzing network connectivity, measuring social distance, and exploring the full reach of relationships in our data.
From Fixed to Variable Paths
In our previous lesson, we used patterns like (alice)-[:FRIENDS_WITH]->()-[:FRIENDS_WITH]->(rec) to find friends of friends. This pattern is explicit about the path length: exactly two hops. If we wanted to find people three hops away, we'd need to write another relationship traversal and, for four hops, yet another.
This approach becomes impractical when we want to answer questions like, "Who is within my extended network?" or "How far is this person from me?" We need a way to express patterns that can match paths of different lengths without writing separate queries for each possible distance.
Variable-length relationships solve this problem. Instead of specifying each hop individually, we can tell Neo4j to follow a relationship type for a range of hops, allowing a single pattern to match paths of varying lengths. This makes our queries more flexible and our analysis more comprehensive.
Visualizing Variable-Length Paths
Before we dive into the syntax, let's visualize what variable-length paths look like:

This diagram shows a simple network with node A as the starting point. Notice how nodes B and C are directly connected to A (1 hop away), node D is reachable through either B or C (2 hops away), and node E sits at the edge of the network (3 hops away). The relationships form a web that demonstrates how a single variable-length pattern can capture connections at multiple distances simultaneously.
Variable-Length Relationship Syntax
Cypher provides a concise syntax for variable-length relationships using the asterisk operator. We specify a minimum and maximum number of hops within the relationship bracket:
This pattern means "follow the FRIENDS_WITH relationship between 1 and 3 times." The range 1..3 tells Neo4j to match paths that are one hop, two hops, or three hops long. We can think of this as a compact way of saying, "Follow this relationship once, twice, or three times."
The syntax is flexible: we can omit the minimum (defaulting to 1), specify exact lengths, or even leave the maximum unbounded, though we'll see why that last option requires caution.
Finding Nodes Within Degrees of Separation
Let's use variable-length relationships to find everyone within Alice's extended network. We'll search for all people reachable within three degrees of separation:
Notice several important aspects of this query. First, we use an undirected relationship -[:FRIENDS_WITH*1..3]- because friendships typically work both ways. Second, we bind the entire matched pattern to a variable called path, which we'll use to calculate distances. Third, we add WHERE me <> other to exclude Alice herself from the results, since a variable-length path of length 0 would match the starting node. Fourth, DISTINCT ensures each person appears only once at each distance.
The length(path) function counts the number of relationships in a path, giving us the distance from Alice to each person.
Understanding Multiple Paths
An important detail: if there are multiple paths of different lengths to the same person, that person will appear multiple times in our results—once for each distinct distance. For example, if Bob is both a direct friend (distance 1) and reachable through a friend-of-a-friend chain (distance 2), we'll see Bob listed twice. This behavior is actually useful because it shows both the shortest path and alternative routes. If we only want the shortest distance to each person, we can use aggregation:
Understanding Path Distance
When we run our query to find people within Alice's network, we see results organized by distance:
The distance values show how many hops separate Alice from each person. Bob and Charlie are direct friends (distance 1); Diana, Eve, and Frank are friends of friends (distance 2); and Grace, Henry, and Iris are three degrees away. This ordering helps us understand not just who is connected to Alice, but how closely connected they are.
The ORDER BY distance clause ensures we see closer connections first, which is often more useful than a random ordering. Closer connections typically represent stronger network relationships.
Path Variables and Functions
Binding a path to a variable, as we did with path = (...), gives us access to powerful path functions. Neo4j provides three essential functions for working with paths:
The length() function we've already used returns an integer count. The nodes() and relationships() functions return lists, allowing us to extract detailed information about everything along the path. These lists preserve the order of traversal, so nodes(path)[0] is always the starting node, and nodes(path)[-1] is always the ending node.
Finding All Paths Between Users
Sometimes, we want to see not just that two people are connected, but all the different ways they're connected. We can find multiple paths by searching for all routes within a certain length, and use list comprehensions to transform the node list into useful information:
The list comprehension [node IN nodes(path) | node.name] iterates through each node in the path and extracts its name property. The result is a list of names showing the complete route from Alice to Bob. Notice we use *..4 here, which defaults the minimum to 1, meaning we'll match paths of 1, 2, 3, or 4 hops.
This query finds all paths from Alice to Bob that are up to four hops long. Each returned row represents a different route through the network. If Alice and Bob have mutual friends or are connected through multiple chains of people, we'll see all these distinct paths in our results.
The ability to enumerate multiple paths reveals redundancy and robustness in networks, showing how many independent routes connect two points. This pattern is particularly useful for visualizing how people are connected or understanding the chain of relationships between two entities.
Visualizing Multiple Paths

This visualization highlights all possible paths between nodes A and E. You can see one path going through B and D (the top route), another through C and D (the bottom route), showing how the two paths converge at node D before reaching E. This convergence and divergence pattern is typical in social networks where people share mutual connections, creating multiple relationship chains between any two individuals.
Understanding Path Results
When we execute our multi-path query, we see each distinct route as a separate row:
Each list shows a complete path from Alice to Bob. In this result, we see a direct connection (1 hop). Depending on the network structure and the maximum path length specified, we might see additional paths that go through different intermediate people, showing the various ways these two users are connected within their social network.
Notice that some paths might be more circuitous than others, even when connecting the same two people. This reflects the reality that social networks often have multiple overlapping connections.
Performance Considerations
Variable-length traversals can be expensive because the number of paths grows exponentially with distance. If each person has 10 friends on average, searching 4 hops deep could potentially explore 10,000 paths. This is why always setting an upper bound is crucial.
Never write unbounded patterns like -[:FRIENDS_WITH*]- in production code. Without a maximum limit, the query might traverse the entire graph, consuming excessive memory and time. Even with bounds, deeper traversals require more resources:
- Depths 1 to 3 are usually safe for most graphs
- Depths 4 to 5 require careful consideration of graph density
- Depths beyond 6 often need specialized approaches or algorithms
Practical Guidelines for Deep Traversals
To keep our queries efficient when working with variable-length paths, we should follow several best practices. First, always specify relationship types and directions when possible; [:FRIENDS_WITH*1..3]-> is much more selective than [*1..3]. Second, add property filters on start and end nodes to reduce the search space.
Third, use DISTINCT judiciously; while it eliminates duplicates, it also requires additional memory. Fourth, consider whether we actually need all paths or just the existence of a connection. Sometimes, asking "Is there a path?" is more efficient than enumerating every possible route.
Finally, use LIMIT to cap the number of results when we're exploring data or showing recommendations. A user interface rarely needs thousands of paths; the top few are usually sufficient.
Conclusion and Next Steps
In this lesson, we've mastered variable-length traversals in Neo4j. We learned the *min..max syntax for flexible path matching, discovered how to measure distances using length(), extracted detailed path information with nodes() and list comprehensions, and understood the performance implications of deep graph traversals.
These techniques enable us to answer sophisticated questions about network connectivity: who is within someone's extended network, what are the shortest or all paths between two people, and how closely connected different parts of our graph are. Combined with our previous knowledge of pattern matching and aggregation, we now have a powerful toolkit for graph analysis.
Time to put these skills into action! The upcoming practice exercises will challenge you to write your own variable-length queries, helping you build confidence in traversing graphs of any depth and complexity.
Note: The query outputs shown throughout this lesson (such as results with Alice, Bob, Carol, etc.) come from the practice database you'll work with in the exercises. The visualizations are simplified diagrams to illustrate concepts.
