2.2.1 Loading, Analysis & Execution

A Bazel build is not one opaque step. It is a pipeline that turns declarations into a plan and only then into artifacts: loading reads the BUILD / .bzl world, analysis turns reachable targets into an action graph, and execution runs the subset of actions whose outputs are actually needed. Keeping those boundaries straight explains how the artifact model from P.2.1 Task-Based vs Artifact-Based becomes the concrete behavior teased in P.2.4 Five Properties.1,2,3

What happens after you run bazel build?
Bazel reads the needed BUILD logic, creates an action plan, then runs the needed actions that are not cached.
load analyze execute
Loading
Read BUILD and .bzl files
Macros expand here
package scope needed packages
Input
Relevant BUILD and .bzl files
Output
Targets with their attribute values
Not yet
No compiler, linker, or test process runs
Analysis
Turn targets into an action plan
Rule implementations run
target graph action graph
Input
Needed targets, attributes, and dependencies
Output
Declared outputs and registered actions
Not yet
Actions are described here, not executed
Execution
Run only the needed actions
Cache hits skip work
local or remote sandboxing
Input
Declared inputs for reachable uncached actions
Output
Artifacts, test logs, and cacheable results
Now
Compilers, generators, linkers, and tests run in parallel
How the objects relate — not a one-to-one conversion
package
loading scope
contains declarations for one or more
targets
configured during analysis
configured target
rule result
may register zero, one, or many
actions
execution units
action
declared work
reads input artifacts and writes declared output artifacts
input artifacts output artifacts
If a behavior changes the graph, it belongs to loading or analysis. If it reads normal inputs and produces files, it belongs to execution.

Loading reads declarations

Loading is where Bazel discovers the structure of the request. It loads the BUILD files for the initial targets and their transitive dependency closure, evaluates the .bzl files reached by load(), and instantiates targets from those declarations. Macros live here: they expand while Bazel is reading BUILD declarations, before any build action runs.2,3,4

For targets in the main repository, this is still not "building" in the everyday sense. Bazel is reading BUILD-related files, not running compilers or other build tools on your source tree. That design is why the reachability story from 2.1.2 Laziness & Slicing already matters at the start: if a package is not reachable from the requested targets, Bazel does not need to load it for this request.3,5

Loading also includes fetching an external repository when Bazel needs a target from it. If a loaded label points into a repository that is not yet available, Bazel runs its repository rule on demand, materializes the repository, and can then continue loading packages from it. This is loading-phase work, not a fourth phase and not a normal build action.6

That repository boundary is the exception to "loading only reads declarations." While materializing an external repository, a repository rule can use host and network APIs, including repository_ctx.execute() for running a host command. Any such command is loading-time repository setup, not an ordinary action in the requested target's action graph. Keep that setup narrow. Once the repository exists, model normal compilation and generation as declared actions.6,7

Analysis turns targets into actions

Analysis takes the reachable target graph from 2.1.1 Nodes, Edges & Acyclicity and asks each rule what it would need in order to produce its outputs. Rule implementation functions run in this phase, validate attributes and dependencies, declare output files, and register actions describing commands plus their declared inputs and outputs.2,4,8

The result is the action graph. It is concrete enough for Bazel to plan caching and parallel execution, but it is still only a plan. Declaring an action does not run it. That is also why rules cannot inspect arbitrary source contents or spawn tools to discover more edges on the fly: loading and analysis define the graph. Execution consumes it. The stronger consequence of that "plan first" model is the topic of 2.2.3 Static Action Graph.2,4,5

Execution runs the needed subset

Execution is where ordinary target build work runs as actions. Bazel starts from the requested outputs, walks backward through the action graph, and runs only the reachable actions that are not already satisfied by valid cached results. Those actions may run locally or remotely, and independent ones can run in parallel.2,3,5,8

At this point tools finally get normal file I/O: compilers read source inputs, linkers produce binaries, tests run, and sandboxes can restrict actions to their declared inputs. That execution-time isolation is the next topic in 2.3.2 Sandboxing. And once you move from "produce declared artifacts" to broader workflow coordination, you have crossed into the territory of 3.7 Workflow Orchestration (Outside the Graph).5,8

Keep the units straight

A useful mnemonic is package -> target -> action -> artifact. Loading works in terms of packages and BUILD declarations. Analysis works in terms of targets, declared outputs, and actions. Execution works in terms of running those actions to materialize artifacts. That is why Bazel can report "packages loaded" and "targets configured" before it ever tells you how many actions ran. 2.2.2 Reading Build Output turns those counters into a practical debugging tool.3

key takeaway

The three phases are not merely labels in a log. They are the mental boundary between "what the build means" and "what the build does": loading reads declarations and fetches required repositories on demand, analysis turns reachable targets into an action plan, and execution runs the uncached part of that plan. If you can place a behavior in the right phase, most Bazel behavior becomes easier to explain.1,2,5,6

Check your understanding · 4 questions

1.Match each build phase to its primary responsibility:

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

Answers
Loading
Analysis
Execution

2.Which phase produces the action graph that execution later runs?

Select one answer

3.Which of the following happen during the loading phase?

Select all that apply

4.A repository rule fetches Haskell sources and invokes the host ghc while creating an external repository. What is the best assessment?

Select one answer

0 of 4 answered

Footnotes

  1. Intro to Bazel — the three-step build process and the action graph as the output of analysis ↩1 ↩2

  2. Extension Overview — loading evaluates BUILD and .bzl files, macros expand there, analysis instantiates actions, and execution runs them only when outputs are needed ↩1 ↩2 ↩3 ↩4 ↩5 ↩6

  3. Build programs with Bazel — request-scoped loading of the dependency closure, user-facing phase descriptions, and the progress counters Bazel prints during builds ↩1 ↩2 ↩3 ↩4 ↩5

  4. Rules — macros are a loading-phase construct, while rule implementation functions run in analysis and register actions instead of executing commands ↩1 ↩2 ↩3

  5. Frequently Asked Questions — no tool execution or arbitrary file I/O during loading or analysis, and only requested outputs cause actions to execute ↩1 ↩2 ↩3 ↩4 ↩5

  6. Repository Rules — repository rule implementations execute in the loading phase when Bazel needs a target from the repository ↩1 ↩2 ↩3

  7. repository_ctx — repository rules can execute host commands. Their loading-time context has different file-I/O powers from ordinary target rules ↩

  8. Writing Bazel rules: simple binary rule — plain-language explanation of the three phases, the file-action graph, and execution-time sandboxing ↩1 ↩2 ↩3