2.2 Three Phases of a Build
Run bazel build //app:server and the terminal can make it look as if Bazel is simply "building now." Then a line appears:
INFO: Analyzed target //app:server (14 packages loaded, 48 targets configured).
That line is the clue that the build has already been doing important work before any compiler error, sandbox failure, or cache hit becomes visible. This section is about learning to split one command into three responsibilities: Bazel first reads declarations, then plans actions, then executes only the uncached part of the plan. Once that boundary is visible, many confusing logs stop being a blur and become a map.
Level 2 has already treated Bazel as a graph in 2.1 Directed Acyclic Graph (DAG). The next step is to see that the graph has layers. A target graph is not yet an action graph. An action graph is not yet executed work. A completed command may reuse previous work at any of those layers.
The Sequence Is A Diagnostic Tool
2.2.1 Loading, Analysis & Execution gives you the vocabulary: loading reads BUILD and .bzl declarations, analysis turns reachable targets into actions, and execution runs those actions when their outputs are needed. Keep its mnemonic close: package -> target -> action -> artifact. It is the shortest way to remember which kind of object belongs to which phase.
2.2.2 Reading Build Output turns that model into a daily triage habit. In a simple phase-separated trace, a failure before INFO: Analyzed ... points toward package, label, BUILD-file, dependency, or rule-validation territory, while a failure after it points toward execution: compilers, linkers, tests, sandboxes, or tools producing outputs. Treat the line as a clue rather than a hard boundary, because Skymeld may start execution for ready targets while analysis of the wider request is still in progress.
2.2.3 Static Action Graph explains why the boundary is stricter than many developers expect. Ordinary rules do not compile first and discover the rest of the build later. Analysis has to register actions, inputs, and outputs before execution starts. That up-front plan is what makes bazel aquery, cache keys, parallel scheduling, and remote execution possible.
2.2.4 Skymeld is deliberately last because it bends the classroom picture without replacing it. Modern Bazel may overlap analysis and execution internally, especially for multi-target builds where some top-level targets finish analysis earlier than others. But Skymeld changes scheduling, not the responsibilities: loading still discovers packages, analysis still prepares actions, and execution still runs them.
Use The Phase Boundary To Choose Evidence
The separation explains several early surprises at once. bazel query can
inspect the target graph without compiling anything. bazel aquery can show
planned commands without running them. A visibility or missing-dependency
failure can stop a build before a compiler starts, while a sandbox failure
belongs to execution because it concerns what a running action can see. The
phase model tells you which evidence can explain the symptom.
Do not read packages loaded as a measure of compilation. It is the shape of the requested package slice becoming visible. Do not read targets configured as commands that ran. It is analysis work. Do not read total actions as "all commands executed from scratch." Cache hits, null builds, and already-valid outputs complicate that number. The counters are useful when read together, in phase order.
Do not use Skymeld as an excuse to abandon the model either. It is true that modern Bazel can overlap more work than the neat diagram suggests. But for a mechanic, the question is usually not "were these milliseconds perfectly sequential?" The question is "which responsibility produced this symptom?" The three responsibilities still answer that question.
Start From The Observed Boundary
Read 2.2.1 Loading, Analysis & Execution first if the words "loading" and "analysis" still feel interchangeable. It is the foundation for the rest of the level, especially 2.3 Hermeticity & Sandboxing, 2.4 Caching & Incrementality, and 2.5 Execution Strategies.
If you are trying to debug a failing command right now, jump next to 2.2.2 Reading Build Output. It gives you the fastest practical move: locate the analyzed-summary boundary, then decide whether to inspect BUILD/graph problems or execution problems.
Read 2.2.3 Static Action Graph when a rule or language integration feels constrained by Bazel's "know the plan first" discipline. That article explains why ordinary Starlark rules cannot use generated file contents to invent the normal graph during execution, and why later escape hatches are treated as special cases.
Treat 2.2.4 Skymeld as optional context unless you are comparing build timings or reading profiles. It matters for performance intuition, but it should not be the first explanation you reach for when a beginner log is confusing.
The eager-fetch-load-edge snippet makes a loading edge visible: its BUILD file loads an external helper, which buildfiles(deps(...)) reveals even though target deps() does not.
Loading discovers packages, analysis turns reachable targets into an action plan, and execution runs the needed actions. Even when Bazel overlaps that work, classifying a symptom by responsibility tells you which logs and debugging tools can explain it.
Sections in this chapter · 4
Loading declarations, analyzing configured targets into actions, and executing the uncached work.
Reading analysis milestones and counters to locate a failure or unexpected amount of graph work.
Why ordinary rules must declare actions, inputs, and outputs during analysis before tools execute.
How Skymeld overlaps ready execution with ongoing analysis without changing phase responsibilities.