aspect cache diff lists the test targets affected by the current working tree by diffing it against your remote cache. It runs no tests. A single Bazel invocation with --experimental_remote_require_cached probes the cache: every cache hit means “unaffected”, and every miss is attributed to the dependent tests.
Strictly a remote-cache operation — no remote build execution (RBE) is required.
When to use it
- Debug cache misses. Find the exact set of cache-missed actions that explain why a CI run rebuilt or re-ran more than expected.
- Validate CI cache coverage. Run it against a clean checkout to confirm your CI is uploading the baseline you expect — a populated cache should report
Affected 0 of N. - Pre-flight a change. Before pushing, list the tests that are actually affected by your edits and pipe them into
bazel testto run only what matters. - Drive selective CI. Use the
linesorjsonoutput to gate downstream jobs on the affected target set.
How it works
- Enumerates the test targets in scope with
tests(<patterns>). - Runs one Bazel invocation with
--experimental_remote_require_cached. Each action’s up-to-date check resolves against the remote cache; on a miss, execution is denied so the probe runs nothing. - Reads the gRPC log of
GetActionResultcalls. A miss anywhere in a test’s transitive closure trips at that action — the frontier. - Attributes the affected tests from the frontier (overreport) or only from missing test actions (precise).
Prerequisites
-
A writable
--remote_cacheconfigured in.bazelrc(or via--bazel-flag). The task fails fast if no remote cache is configured. -
A populated baseline: a cache hit is what makes a target “unaffected”, so the mainline’s action results must already be uploaded. Normally this happens as a byproduct of regular CI:
Seed on a clean checkout (or a fresh
--output_base) — on a warm output base Bazel finds everything locally cached, executes nothing, and uploads nothing. CI checkouts are cold, so this is automatic there. -
The probe and the baseline must resolve the same Bazel flags, so they compute the same action digests. The probe reuses the same rc/config as
aspect build/aspect test, so they line up by default. A flag that changes an action’s environment (for example--action_env=FOO) must be present on both sides or neither.
Modes
Pick a mode with--mode:
| Mode | What it does | Cost |
|---|---|---|
overreport (default) | Reverse-deps from each cache-missed target to its dependent tests. | Runs nothing. May flag a test even when its dependency would rebuild to an identical output. |
precise | First runs bazel build to build and upload the missing non-test actions, then flags a test only when its own test action misses. | Costs the build of the missing non-test actions. Narrows the result to genuine input changes. |
overreport executes nothing; precise executes only the missing non-test actions (it builds with bazel build, which cannot execute TestRunner). The lone exception is actions tagged no-remote, local, no-remote-exec, or no-cache — those bypass the remote path entirely, so they run locally and read as affected.
Output
By default, affected labels stream to stdout, one per line:--exec:
Affected X of N test target(s). summary go to stderr.
Configuration flags
| Flag | Default | Description |
|---|---|---|
--mode | overreport | overreport or precise. See Modes. |
--format | lines | lines (one label per line) or json (single document on stdout). |
--exec | (empty) | Run the given command with the affected labels appended as arguments (for example --exec="bazel test"). No-op when nothing is affected. Overrides --format. |
--bazel-flag | — | Additional Bazel flags forwarded to the probe and the precise build (for example --bazel-flag=--config=ci). Repeatable. |
--bazel-startup-flag | — | Additional Bazel startup flags. Repeatable. Note that changing startup flags restarts the Bazel server. |
| positional | //... | Target patterns scoping the affected set (intersected with tests(<patterns>)). |
aspect cache diff --help for the complete list of flags.
Examples
Scope to a sub-tree and run only the affected tests:overreport noise to genuine input changes:
Soundness and limits
The result is bounded by your baseline’s cache coverage:- A hit means the target is unaffected.
- A miss means the target is either changed or never-uploaded/evicted.
overreport over-reports and precise narrows the result to genuine input changes.
The probe runs with --nokeep_state_after_build --nouse_action_cache, which forces a fresh remote GetActionResult per action — so the command runs on the default output base with no separate or wiped base.
Related
aspect build&aspect test— the same task lifecycle that seeds the cache baseline.- Aspect Workflows — Aspect Workflows runners auto-configure the remote cache that
aspect cache diffreads from.

