2.1.5 Inspecting the Graph — Query Preview

recommended

The earlier items in this section used bazel query tactically: inspect a reachable closure, trace a path, or check who depends on what. The missing map is that Bazel exposes three related inspectors, each attached to a different graph layer. <a class="cross-ref" href="/book/1~1~8" title="1.1.8 Basic Query"><span class="cross-ref-id">1.1.8</span> Basic Query</a> introduced the first one. At this level, the useful upgrade is to line all three up with the DAG model: query reads the declared target graph, cquery reads the configured target graph after analysis, and aquery exposes the action graph that analysis produced. They let you inspect Bazel's model without running the compile, link, or test actions themselves.1,2,3,4

Which graph should I inspect?
Start with the question you need to answer, then choose the matching Bazel query tool.
//my:target

The same label appears in three increasingly concrete graph views.

bazel query
Declared target graph
After loading
bazel query 'deps(//my:target)'
bazel cquery
Configured target graph
After analysis
bazel cquery 'deps(//my:target)'
bazel aquery
Action graph
Before execution
bazel aquery '//my:target'
query for declared structure, cquery when configuration matters, aquery for the actions Bazel plans to run.

One target, three different questions

The easiest way to remember the query family is by question, not by command name. Relative to the build phases in 2.2.1 Loading, Analysis & Execution:

  • bazel query works on the post-loading target graph. It is the right first tool for deps(), rdeps(), somepath(), and allpaths() questions about the declared structure.1,5
  • bazel cquery runs after analysis, so it resolves select(), build flags, and configuration-specific dependency choices. Its results include configuration IDs because the same label can appear in more than one configuration.2
  • bazel aquery shows the actions analysis registered: mnemonics, inputs, outputs, and command lines. It is the lowest-level graph view before execution starts.3

Start with query

For most DAG questions in this level, query is still the default. It is cheaper than the other two because it stops at the declared graph, and it already answers the structural questions from this chapter: reachable closure, reverse dependencies, and dependency paths.1,5

bazel query 'deps(//my:target)'
bazel query 'rdeps(//..., //lib:core)'

When the result gets noisy, --noimplicit_deps trims rule-injected and toolchain edges so you can focus on the dependencies you actually wrote in BUILD files.1,5

think

Compare: A target's deps uses select() with mutually exclusive Linux and macOS branches. bazel query 'deps(//pkg:tgt)' prints labels from both branches. Did Bazel just tell you this build will compile both?

Reveal

No. Plain query proved that both labels are possible declared edges of the target. It did not prove that one configured build will compile both branches. query runs before configuration is resolved, so it answers "could this target reach that label?" rather than "did this flag set choose that edge?"

That overapproximation is useful when you are hunting broad structural relationships. If the real question is "which branch does Linux CI choose?", switch to cquery for the configured target.

That is the trade-off: query is intentionally conservative. Because it runs before configuration is applied, it can show more possibilities than a specific build will actually choose.1,2

Switch to cquery when configuration matters

That conservative behavior is exactly where cquery starts being useful. If a target uses select(), build flags, or platform-dependent toolchains, plain query answers "what could happen?" while cquery answers "what did this build configuration choose?".2,4

The nice part is that the expression often stays the same:

bazel query 'deps(//my:target)'
bazel cquery 'deps(//my:target)'

What changes is the graph layer. cquery runs over configured targets after analysis, so it can distinguish cases that the loading-phase graph has to overapproximate. That extra precision costs more time and memory than query, which is why query stays the better first look when configuration is not the issue.2,6

Use aquery when you need the action plan

aquery drops below targets and into actions. Instead of telling you only that //my:target eventually depends on a compiler or code generator, it shows the concrete actions Bazel registered for the build: compilation steps, link steps, generated outputs, command lines, and mnemonics.3,4

bazel aquery '//my:target'

This is the preview-level answer to "what will Bazel actually do for this target?" Later, 5.2 Query goes deeper into action-specific filters such as mnemonic(), inputs(), and outputs(), plus the heavier-duty workflows that turn query output into debugging or CI tooling.3,6

key takeaway

Use query for declared structure, cquery when the answer depends on configuration, and aquery when you need the concrete action plan. The detailed recipes live in 5.2 Query. The point here is the map: one build, three graph layers, three matching inspection tools.4,6

Check your understanding · 3 questions

1.Match each query tool to the graph layer it operates on:

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

Answers
bazel query
bazel cquery
bazel aquery

2.When should you prefer bazel cquery over bazel query for a dependency question?

Select one answer

3.True or false: characteristics of the three query tools.

Choose True or False for each sentence

bazel aquery shows planned actions without running any compile or test commands.
bazel query is more expensive than bazel cquery because it loads more packages.
0 of 3 answered

Footnotes

  1. The Bazel Query Referencequery as post-loading target-graph inspection, plus implicit-dependency and overapproximation semantics 1 2 3 4 5

  2. Configurable Query (cquery) — analysis-phase configured graph, configuration IDs, and select() resolution 1 2 3 4 5

  3. Action Graph Query (aquery) — actions, artifacts, mnemonics, command lines, and the relation to the configured target graph 1 2 3 4

  4. A guide to Bazel query — practical three-layer mental model and mapping to loading, analysis, and action inspection 1 2 3 4

  5. Query guidedeps(), rdeps(), path queries, and --noimplicit_deps 1 2 3

  6. Deep dive into Bazel queries: from basics to advanced use cases — preview-oriented explanation of query, cquery, and aquery, including why cquery is the heavier tool 1 2 3