5.2.4 bazel config — Configuration Inspection

extra

cquery tells you which configuration a configured target uses. bazel config opens that configuration and shows the option values inside it. Together they turn an opaque suffix such as (3a0f53e) into evidence you can compare with a config_setting or a transition.1

The command is an experimental, unsupported diagnostic interface in Bazel 9.0, so treat its text layout and Java fragment names as human-readable debugging output, not a stable API for production tooling.2

Preserve the configuration you want to inspect

bazel config does not reconstruct an arbitrary historical configuration from its hash. It looks for configuration objects still present in the current Bazel server's Skyframe cache.2 Generate the configured graph first, then inspect it immediately:

bazel cquery 'deps(//app:server)' --platforms=//platforms:linux
//app:server (3a0f53e)
//app:linux_runtime (3a0f53e)
...
@@platforms//host:host (3030ed4)

This example comes from the runnable select-errors snippet. Its select() chooses the Linux runtime under the requested target platform. The short hexadecimal text in parentheses is a configuration ID. It identifies the configuration attached to that result. It is not a label and should not be interpreted as an action or remote-cache key.

Pass that ID to config, keeping the build options from the cquery invocation:

bazel config 3a0f53e --platforms=//platforms:linux

The repeated option is operationally important. Changing the command-line options can invalidate the cached configuration nodes before config reads them. Bazel's official debugging guidance therefore says to invoke both commands with the same flags.1 In a real repository, that includes the named configs and other build options that established the context, not just the one flag that looks relevant.

With no ID, bazel config lists the configurations currently available in the server. This is useful when output has scrolled away or when you want the full ID behind a short prefix:

bazel config --platforms=//platforms:linux
Available configurations:
...
3030ed4c810cf3435d066294fa495e650fe75173e4b4ef410ea56cb683458569 fastbuild-noconfig (test-trimmed)
3a0f53e6285b4e814e79d042cc4be4b18d31f67188527ee2e25f4e2cc5981c68 k8-fastbuild (test-trimmed)

The exact IDs and mnemonic descriptions depend on the workspace, host, flags, and Bazel version. Use them only as identifiers from your own invocation.

Find the value that decides a select()

Text output groups values into configuration fragments and fragment-option classes. The implementation-shaped headings are less important than the option names and values beneath them. For the example above, the relevant entry is:

FragmentOptions com.google.devtools.build.lib.analysis.PlatformOptions {
  platforms: [//platforms:linux]
  ...
}

Read the output against the condition you are debugging:

  1. Use cquery in the real top-level context to obtain the configured target instance, as described in 5.2.2 bazel cquery — Configured Graph.
  2. Inspect that instance's configuration ID with the same flags.
  3. Find the built-in option, --define value, platform selection, or user-defined Starlark flag referenced by the candidate config_setting.
  4. Compare the value with every requirement of that condition. A config_setting matches only when all of its specified requirements match.1

This separates two questions that are easy to blur. cquery proves which branch and dependency edge Bazel selected. bazel config shows the values that the condition was evaluated against. 3.3.1 Configurable Attributes (select()) defines the matching rules in depth.

For scripts or focused inspection, Bazel 9.0 also accepts --output=json:

bazel config 3a0f53e --platforms=//platforms:linux --output=json

The JSON separates metadata such as configHash, mnemonic, and isExec from fragment options and the user-defined options map.2 This is preferable to scraping Java class headings from the text form, but the command itself remains experimental and unsupported.

Diff configurations before blaming a transition

When the same label occurs in two configurations, pass both IDs. Bazel prints the option differences instead of two full dumps:2

bazel config <first_id> <second_id> <the same build flags>

This is the fastest way to reduce “why is this dependency configured twice?” to a concrete set of differences. For a Starlark transition, first use cquery --transitions=lite to locate the edge, then diff the configurations on the two sides. If the changed options agree with the transition's declared outputs, the transition is behaving as specified. If an expected change is missing or an unexpected one appears, inspect the transition implementation described in 4.7.2 Starlark Transitions.

Do not assume every line in a large diff was directly written by that transition. Configurations can also differ because of exec transitions, 4.6.3 Toolchain Resolution, platform selection, option defaults, trimming, or other transitions along the path. Use the graph edge from cquery to establish provenance, then use the config diff to inspect state.

Keep the investigation narrow: identify two configured target instances on one specific path, preserve their exact invocation flags, and diff those two IDs. Dumping every available configuration produces plenty of data but little causal evidence.

Know when to switch tools

bazel config explains configuration state. It does not explain the rc-file layers that supplied command-line options. Use --announce_rc and 3.2.1 .bazelrc Hierarchy for that. It also does not show the final compiler or linker command generated from those values. Use 5.2.3 bazel aquery — Action Graph for the action plan.

If config reports that an ID cannot be found, rerun the producing cquery and then config without changing flags or server state. A shutdown, an invocation whose options invalidate analysis state, or simply inspecting an ID from a different output base leaves no cached object for this command to display.1

key takeaway

Use bazel config immediately after cquery, with the same build flags, to turn a configured target's ID into inspectable option values. Compare those values with config_setting requirements to explain a select(), or pass two IDs to isolate configuration differences around a transition. The command reads the current server's Skyframe cache and remains experimental in Bazel 9.0, so its output is diagnostic evidence rather than a stable automation contract.

Check your understanding · 4 questions

1.A developer saves a configuration ID from yesterday, restarts Bazel, and runs bazel config with that ID. Bazel cannot find it. What should the developer do?

Select one answer

2.A cquery run used --config=ci --platforms=//platforms:linux. Which practices help keep its configuration available for the following bazel config inspection?

Select all that apply

3.The same label appears under two configuration IDs after a suspected Starlark transition, and a select() chose an unexpected branch. What is the strongest next diagnostic step?

Select one answer

4.Match each investigation to the tool that answers it most directly:

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

Answers
Which configured dependency and select() branch did Bazel choose?
Which option values differ between these two cached configurations?
What final compiler command and inputs did analysis register?
0 of 4 answered

Footnotes

  1. Configurable build attributes — the cquery plus bazel config debugging workflow, configuration-cache requirement, matching semantics, and same-flags warning 1 2 3 4

  2. Command-Line Reference — Bazel 9.0 config command syntax, zero/one/two-ID modes, diff behavior, JSON output, and experimental status 1 2 3 4