2.1.6 Reverse Dependencies & Change Impact

recommended

2.1.5 Inspecting the Graph — Query Preview mapped query, cquery, and aquery to three graph layers. The missing DAG question at this point is the reverse one: after 1.1.8 Basic Query taught forward deps() walks, how do you ask "who depends on this target?" Plain bazel query answers that with rdeps(), which walks backward through the declared target graph inside a universe you choose.1,2,3

Same graph, opposite question
deps() walks from a requested target to its prerequisites. rdeps() starts from a shared target and asks which dependents or consumers use it.
deps()
What does this target need?
Forward prerequisite walk
bazel query "deps(//services/payment:payment)"
//services/payment:payment
//services/payment:payment_lib
//lib/logging:logging
Start from the requested build target, then follow edges toward what must already exist.
rdeps()
Which targets depend on this one?
Walk toward dependents
bazel query "rdeps(//..., //lib/logging:logging)"
//services/auth:auth_lib
//services/payment:payment_lib
//services/user:user_lib
//lib/logging:logging
Start from the shared target. The universe is the set of targets that rdeps() searches only within the supplied universe. //... makes that universe the whole workspace.
The target graph stays the same. The difference is the question: deps() finds prerequisites, while rdeps() finds targets that may be affected by a change.

rdeps() flips the question

deps(x) asks what target x needs. rdeps(u, x) asks which nodes in universe u depend on x. The first argument is the part beginners usually miss: reverse dependencies are always computed inside a chosen universe, not across some implicit "whole Bazel world". Using //... makes the universe the whole workspace. A narrower scope keeps the answer closer to the change you are about to make.1,2,4

bazel query "rdeps(//..., //lib/logging:logging)"
bazel query "rdeps(//foo, //common, 1)"

The optional third argument is a depth bound. rdeps(//foo, //common, 1) asks for direct reverse dependents only. Omitting the depth asks for the full reverse closure inside the chosen universe.2

Use it before you refactor or delete

This makes rdeps() a change-impact query, not just a graph curiosity: the practical question it answers is what other code you are about to break. A shared logging library is the classic example — before changing it, ask which libraries and binaries depend on it.1,3

bazel query "kind('go_binary', rdeps(//..., //lib/logging:logging))"

Filtering the reverse closure by kind is often enough to turn a noisy answer into an actionable one. If you are touching a shared library, maybe you care about binaries. If you are changing test support code, maybe you care about test targets. The DAG question stays the same: which targets use or transitively depend on this one?1,3

Use the right graph question

rdeps() is about impact radius, not explanation. If the question is "why does A depend on B?", use somepath() or allpaths() from 2.1.4 Common Dependency Issues. If the question is "what does this configured build really choose?", the deeper handoff is 5.2 Query: plain query stays on the declared target graph, while later tools handle configuration-aware and action-level questions.1,2,3

Later, 6.5.1 Affected-Target Service Contract turns the same reverse-dependency idea into affected-target workflows for CI. At Level 2, the mechanic is simpler: pick a universe, walk the graph backward, and narrow the result until it matches the kind of change you are making.3

key takeaway

Use deps() for prerequisites and rdeps() for change impact. The moment you want to know "who uses this target?" or "what might this refactor break?", choose a universe first, then ask the reverse question.1,2

Check your understanding · 3 questions

1.What does the universe argument in rdeps(universe, target) control?

Select one answer

2.True or false: using rdeps() in practice.

Choose True or False for each sentence

rdeps(//..., //lib:core) answers 'who depends on //lib:core in the entire workspace?'
Adding a depth bound like rdeps(//..., //lib:core, 1) returns the full reverse transitive closure limited to one package.

3.You are about to refactor //lib/logging:logging. Which query expression best identifies which binaries might break?

Select one answer

0 of 3 answered

Footnotes

  1. Query guiderdeps() as the answer to "what other code are you about to break?", plus practical reverse-dependency filtering 1 2 3 4 5 6

  2. The Bazel Query Reference — exact rdeps(universe, target[, depth]) semantics, universe scoping, and optional depth bound 1 2 3 4 5

  3. A guide to Bazel query — concrete rdeps() examples for refactors, binaries, and change-impact questions in a monorepo 1 2 3 4 5

  4. Query quickstart — beginner explanation of reverse dependencies, whole-workspace //... scope, and why rdeps() matters before edits