2.1.6 Reverse Dependencies & Change Impact
recommendeddeps() asks what a target needs. rdeps() asks who depends on that target,
walking backward through the declared target graph inside a universe you
choose. 1.1.8 Basic Query introduced basic forward walks, and
2.1.5 Inspecting the Graph — Query Preview placed plain query on the declared target graph. Here,
the practical question is what a change might affect.1,2,3
deps() walks from a requested target to its prerequisites. rdeps() starts from a shared target and asks which dependents or consumers use it.
rdeps()
starts at the highlighted prerequisite and traverses those edges
backward. //... makes the search universe the whole workspace.
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.7.1 Selecting Affected Targets 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
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?'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
Footnotes
-
Query guide —
rdeps()as the answer to "what other code are you about to break?", plus practical reverse-dependency filtering ↩1 ↩2 ↩3 ↩4 ↩5 ↩6 -
The Bazel Query Reference — exact
rdeps(universe, target[, depth])semantics, universe scoping, and optional depth bound ↩1 ↩2 ↩3 ↩4 ↩5 -
A guide to Bazel query — concrete
rdeps()examples for refactors, binaries, and change-impact questions in a monorepo ↩1 ↩2 ↩3 ↩4 ↩5 -
Query quickstart — beginner explanation of reverse dependencies, whole-workspace
//...scope, and whyrdeps()matters before edits ↩