2.5 Execution Strategies
bazel build //app:server --spawn_strategy=sandboxed and bazel build //app:server --strategy=Javac=worker,local look like they might be changing what gets built. They are not. They change how Bazel runs already-planned actions: directly in the execroot, inside a sandbox, through a long-lived worker process, on remote machines, or by trying more than one path and taking the result that finishes first.
Earlier Level 2 chapters built the model up to the action boundary: the target graph in 2.1 Directed Acyclic Graph (DAG), the loading-analysis-execution split in 2.2.1 Loading, Analysis & Execution, hermeticity in 2.3.1 Hermeticity, and cache identity in 2.4.3 What Makes a Cache Hit. Execution strategies sit after that planning work. They are the policy layer for running actions, not a second language for defining targets.
The Policy Layer After Analysis
2.5.1 Strategies Abstraction gives the model: analysis decides which actions exist, which inputs they declare, and which outputs they promise. Strategy decides where and under what constraints those actions run during execution. That is why a repository can move from local builds to sandboxed CI, persistent workers, or remote execution without rewriting every BUILD file. If changing strategy changes output bytes, the strategy did not define a new build. It exposed a hidden input, unstable tool, or other break in the action contract.
2.5.2 Strategies & Mnemonics then gives the names you need to read logs and flags. Strategies such as local, sandboxed, worker, remote, and dynamic describe execution modes. Mnemonics such as Javac, CppCompile, and Genrule name action kinds. The useful reading pattern is to pair them: --spawn_strategy=sandboxed sets a default execution mode, while --strategy=Javac=worker,local routes one action kind through a more specific strategy chain.
If --strategy=Genrule=local makes a failure disappear, the action did not gain
new build logic. The comparison usually exposes a dependency on the
unconstrained host environment. That diagnosis leads back to
2.3.2 Sandboxing and 2.3.4 First-Response Debugging Flags, not to a permanent local
strategy exception.
This interchangeability connects hermeticity to later scale choices. Persistent workers and remote execution can change how actions run safely only when their meaning is already fixed. 6.3 Remote Execution Infrastructure and 6.4 Execution Modes and Persistent Workers make those policies operational at scale.
Why This Feels Slippery
The vocabulary mixes layers that appear in the same log line. A strategy name tells you where or how an action ran. A mnemonic tells you what kind of action it was. A sandbox backend such as darwin-sandbox, linux-sandbox, or processwrapper-sandbox may be the concrete implementation behind a broader sandboxed choice. A project .bazelrc may set all of this before you ever type the flag yourself.
That pile of names becomes manageable if you keep two questions separate. First: "which action kind is this?" That is the mnemonic. Second: "which execution environment did Bazel choose for it?" That is the strategy. Configuration mechanics such as shared defaults and named configs belong in 3.2 Project Configuration. This section only gives you the conceptual vocabulary to understand what those configs are saying.
Start From The Symptom, Not A Strategy Flag
Read 2.5.1 Strategies Abstraction first if you are still building the under-the-hood model. It explains why the action graph is stable before strategy selection, and why hermeticity is the contract that makes strategy changes safe.
Read 2.5.2 Strategies & Mnemonics when you are looking at real output, .bazelrc, or a debugging suggestion. It gives you the operator vocabulary for lines like Javac=worker,local, Genrule=local, and --spawn_strategy=sandboxed.
If you are debugging a failed action, do not start here. Start with 2.3.4 First-Response Debugging Flags to see the command and sandboxed filesystem, then come back when the proposed workaround mentions --spawn_strategy or --strategy. If the build succeeds but rebuilds unexpectedly, 2.4.4 Diagnosing Cache Misses is the better first stop. Execution strategy is often part of the story, but the first diagnostic question should match the symptom.
Decide: One build becomes faster after adding
--strategy=Javac=worker,local. What hypothesis does that experiment test, and
what evidence would justify keeping the strategy?
Reveal
The hypothesis is that repeated Java compile actions can amortize tool startup or initialization through a persistent worker. Compare repeated representative runs with the same target, flags, cache state, and edit scenario. Confirm in the profile that the expected execution cost falls, and verify that the tool supports the worker protocol while preserving hermetic, deterministic outputs. One faster run is not enough evidence for repository-wide policy.
Analysis defines the action, its mnemonic names the action kind, and the strategy chooses how that action runs. Local, sandboxed, worker, remote, and dynamic execution are policies over the same build model, not different ways to define the build.