5.2.6 Sky Query Mode

recommended

Some repository-wide questions are awkward for ordinary bazel query: reverse dependency searches need an explicit universe expression, and finding every BUILD file that loads a changed .bzl file requires edges outside the ordinary target graph. Sky Query is a mode of bazel query that evaluates against a declared universe by inspecting Bazel's existing Skyframe graph. It adds allrdeps() and rbuildfiles() and can, in some circumstances, use less memory or run faster than the default query implementation.1

That is a conditional advantage, not a repository-size threshold. There is no documented target count at which Sky Query becomes necessary, and it is not a general cure for an expensive expression. Choose it when its universe-scoped operators answer the question directly, or benchmark it when ordinary query's separate graph is the suspected cost.

Reverse-impact answers cannot escape the Sky Query universe
Choose the consumer universe before walking target dependencies or Starlark load relationships in reverse.
--universe_scope=//... --order_output=no
EXPLICIT UNIVERSE · TRANSITIVE CLOSURE
ALLRDEPS() · TARGET CONSUMERS
//app:runner
//lib:core
Result consumer ← reverse walk from seed
RBUILDFILES() · REVERSE LOAD DEPENDANTS
//app:BUILD
tools/lint/rules.bzl
Returned BUILD-file target ← path-fragment argument
allrdeps() uses target labels rbuildfiles() takes path fragments
EXCLUDED CONSUMER
Reverse answer disappears
Outside inferred closure
//app:runner
INFERRED UNIVERSE
Seed closure is too narrow
Consumer not preloaded
allrdeps(//lib:core)
Declare the consumer universe for reverse-impact work. Inference from the changed target can exclude consumers before evaluation begins. Treat output as an unordered set.

Activate the mode with both required flags

Sky Query requires two choices: a universe and unordered output. Supply either --universe_scope or --infer_universe_scope, and set --order_output=no:1

bazel query \
  --universe_scope=//... \
  --order_output=no \
  'allrdeps(//lib:core)'

--universe_scope accepts a comma-separated list of additive and subtractive target patterns. Bazel preloads the transitive closure of those roots, then evaluates the expression inside that scope. The universe is therefore a graph closure, not merely a package-name filter.1 This is the same distinction that matters for rdeps() in 5.2.1 bazel query — Static Graph Analysis, but the universe moves from the function's first argument to the command line.

The basic-query snippet makes that visible. With --universe_scope=//..., allrdeps(//lib:core) returns the library and the targets in the snippet that transitively depend on it. Narrowing the universe to one application root deliberately excludes consumers outside that root's dependency closure.

In a fresh Bazel 9.0.0 process, the snippet's explicit command produced this result (Sky Query output order is not significant):

//lib:core
//service:menu
//config:app_config
//app/data:repo
//app:runner
think

Predict: What does this command find?

bazel query --infer_universe_scope --order_output=no \
  'allrdeps(//lib:core)'
Reveal

Usually only //lib:core. Inference extracts the unique target patterns from the expression, so the inferred universe is the dependency closure of //lib:core itself. Reverse consumers are not in that universe by construction. In a fresh process, the snippet command produced:

//lib:core

--infer_universe_scope is safe only when the target patterns already embedded in the whole expression describe the intended consumer roots. For reverse impact analysis, spell out the universe unless you have inspected what inference will select.1

One local Bazel 9.0.0 observation adds a practical testing caveat: after the same long-lived server evaluated the broad explicit-universe command above, the inferred command also emitted reverse consumers that the broad query had loaded. A fresh bazel --batch query --infer_universe_scope --order_output=no 'allrdeps(//lib:core)' process returned only //lib:core. This is evidence from that version and snippet, not a general guarantee about other releases. Use a fresh process or server when correctness-sensitive comparisons need to isolate universe inference from warm Skyframe state.

Use allrdeps() when the universe is already a command-level decision

allrdeps(x) computes the transitive reverse dependencies of x in the command's universe. It also accepts an optional maximum depth:

# The changed target plus direct consumers in the selected product areas
bazel query \
  --universe_scope=//app/...,//service/... \
  --order_output=no \
  'allrdeps(//lib:core, 1)'

Given --universe_scope=//foo/..., allrdeps(//bar) is equivalent in set semantics to rdeps(//foo/..., //bar).1 The benefit is not that it performs an unconstrained global search. It makes one deliberately selected universe available to universe-scoped operators without repeating it inside each call.

Start with the smallest universe that contains every consumer relevant to the decision. A narrow universe is faster to load but can produce a confidently incomplete answer. A repository-wide universe is broader evidence but may cost substantially more. Add a depth bound when direct or near-direct consumers are all the investigation needs. 2.1.6 Reverse Dependencies & Change Impact introduces the change-impact interpretation of reverse edges. Sky Query changes how the universe is supplied, not what a reverse dependency means.

Use rbuildfiles() for reverse load dependencies

rbuildfiles() answers a different question: which BUILD files transitively depend on these BUILD or .bzl path fragments?

bazel query \
  --universe_scope=//... \
  --order_output=no \
  'rbuildfiles(tools/lint/rules.bzl)'

If packages load tools/lint/rules.bzl, the result contains their BUILD-file targets. Transitive load chains are followed, so a BUILD file that loads an intermediate .bzl file can also be returned. Arguments are workspace-relative path fragments, not labels. Ordinary source files such as foo.cc are ignored. the operator is about package-definition and Starlark load dependencies.1

This is useful when changing a shared macro or rule definition and deciding which packages need further inspection. It is not by itself a configured impact analysis: it finds loading relationships, while 5.2.2 bazel cquery — Configured Graph resolves configured target edges and 5.2.3 bazel aquery — Action Graph inspects generated actions. A CI pipeline may use rbuildfiles() as one input to target determination. See 6.5.1 Affected-Target Service Contract for the complete pipeline and its correctness policy.

Treat unordered output as part of the contract

Sky Query cannot preserve graph-ordered presentation. --order_output=no may print compatible formats in arbitrary order, and --output=graph, --output=minrank, and --output=maxrank are forbidden in this mode.1

For a person, sort labels after the query when alphabetical presentation helps:

bazel query --universe_scope=//... --order_output=no \
  'allrdeps(//lib:core)' | sort

For automation, treat results as a set. Do not infer dependency order from line position, and do not make a diff depend on the raw emission order. If the next step needs graph rendering or ranked output, use ordinary query with an appropriate rdeps() universe instead.

Choose Sky Query from evidence, not assumptions

Sky Query introspects Skyframe instead of constructing the separate graph used by default query. Official documentation promises only that this is faster and uses less memory in some circumstances.1 It does not promise lazy or parallel evaluation, immunity from out-of-memory failures, or a fixed scale at which it wins.

A defensible operating sequence is:

  1. State the required consumer roots or package-definition scope.
  2. Use ordinary rdeps() when its explicit universe is clear and sufficient.
  3. Use Sky Query for allrdeps() or rbuildfiles(), or benchmark it against the default implementation for the actual expression and repository state.
  4. Narrow universe roots and add a depth bound when that still answers the question. Do not narrow merely to make a command finish if it invalidates the answer.
  5. Record the universe alongside saved results. Without it, another reader cannot tell what the query was capable of finding.
key takeaway

Sky Query is an unordered, universe-scoped mode of bazel query. Activate it with --order_output=no plus either an explicit or inferred universe. Prefer an explicit universe for reverse-impact questions, because inference can exclude the very consumers you want to find. Use allrdeps() for reverse dependencies within that universe and rbuildfiles() for reverse BUILD/.bzl load relationships. Treat performance as a measured, workload-specific benefit—not as a guaranteed consequence of repository size.

Check your understanding · 4 questions

1.Which flag combination activates Sky Query mode?

Select one answer

2.Why can inferred universe scope make allrdeps(//lib:core) miss consumers of //lib:core?

Select one answer

3.Match each Sky Query operator to the relationship it follows:

Drag each answer onto the matching prompt, or click an answer and then click a prompt

Answers
allrdeps(//lib:core)
rbuildfiles(tools/lint/rules.bzl)

4.How should callers handle Sky Query results?

Choose True or False for each sentence

Automation should treat the result as an unordered set.
A label appearing first is necessarily closer to the query seed.
Callers may sort labels afterward when stable presentation is useful.
Graph, minrank, and maxrank output remain available in this mode.
0 of 4 answered

Footnotes

  1. The Bazel Query Reference — Sky Query activation, universe semantics and inference caveat, allrdeps() and rbuildfiles() behavior, performance qualification, and unordered-output restrictions 1 2 3 4 5 6 7 8