2.4.1 Skyframe & Incrementality
Skyframe is the concrete mechanism behind the incrementality teaser from P.2.4 Five Properties and the warm-server behavior from 1.1.3 Server/Client Architecture. Bazel keeps build state as immutable nodes in an evaluation graph held by its long-lived server, so when an input changes it can invalidate only the affected chain instead of planning the whole world again.1,2,3
Skyframe nodes stay in memory. Later build-style commands reuse loading and analysis where inputs still match.
A new server rebuilds Skyframe from scratch. Disk and remote caches can still reuse action outputs.
More than the target DAG
The target DAG from 2.1.1 Nodes, Edges & Acyclicity is only one slice of what Bazel needs to remember. Skyframe also tracks file state, package parsing, configured targets, artifacts, and action executions.1 That broader graph is why incrementality spans the loading, analysis, and execution flow from 2.2.1 Loading, Analysis & Execution, not just the final compiler step.1,3
At this level, the useful mental model is "Bazel remembers build state, not just outputs." If you edit a BUILD file, Bazel can invalidate package and configured-target state before any tool runs. If you edit a source file, Bazel can often keep earlier analysis work and reconsider only the downstream actions that depend on that file.1,3
What happens when one file changes
Skyframe starts conservatively: everything that depends on the changed input becomes potentially dirty, while unrelated parts of the graph stay clean.1,4 Bazel then reevaluates the affected nodes and compares their new values with the old ones.
That second step is why incrementality is better than "rebuild every downstream target." Bazel calls this change pruning: if a node was invalidated but recomputes to the same value, Bazel can stop the damage there and keep its dependents clean.1 The intuition is simple: if an edited library still produces the same compiled output, the binary above it does not need to be relinked.4
This answers a different question from 2.1.2 Laziness & Slicing. Laziness asks which part of the graph belongs to the current request. Skyframe incrementality asks what inside that already-known slice actually became dirty since the last command.
Why warm builds feel faster
Skyframe lives in server memory, not in your repository. The long-lived Bazel server keeps state across commands, which is why warm-server reuse makes query fast by reusing loaded-package state, and lets build, run, and cquery skip a lot of repeated loading and analysis work.2,3,5
bazel build //app:server
bazel build //app:server
bazel shutdown
bazel build //app:server
The second command can reuse in-memory analysis state. After bazel shutdown, an idle-timeout shutdown, or a server restart triggered by startup-option changes, that in-memory graph is gone, so the next command is cold on loading and analysis again.2,3 That does not automatically mean every action reruns: persistent caches can still validate outputs from the output tree or elsewhere. The cache-layer taxonomy comes next in 2.4.2 Where Bazel Caches Things, and the exact reuse key comes after that in 2.4.3 What Makes a Cache Hit.3,5
This is also why flag churn hurts iterative workflows. Many options affect the build graph, so switching flag sets mid-session can discard the analysis cache even when the files you care about did not change.3
The names you'll meet later
The three core pieces are SkyValue (an immutable stored value), SkyKey (the stable name for that value), and SkyFunction (the computation that produces it from dependencies). That vocabulary matters in 5.9 Skyframe, but for Level 2 the important idea is simpler: Bazel records dependency-linked build results precisely enough to reevaluate only the affected ones.1
Check your understanding · 3 questions
1.What is change pruning in Skyframe, and why does it matter for incremental builds?
Select one answer
2.True or false: Skyframe scope and behavior.
Choose True or False for each sentence
bazel shutdown discards the in-memory graph and makes the next build cold on loading and analysis.3.Why does switching build flags frequently slow down iterative workflows even when source files have not changed?
Select one answer
Footnotes
-
Skyframe — immutable node model, evaluation graph, bottom-up invalidation, and change pruning ↩1 ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8
-
Client/server implementation — long-lived server caching of build metadata across invocations, idle shutdown, and restart behavior ↩1 ↩2 ↩3 ↩4
-
Optimize Iteration Speed — analysis cache in server memory, cold versus warm builds, and cache discard from flag changes ↩1 ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8
-
Trimming the Build Tree with Bazel — upward transitive closure invalidation and stopping when a rebuilt dependency's output is unchanged ↩1 ↩2
-
The Many Caches of Bazel — Skyframe as Bazel's in-memory cache and the distinction between that cache and persistent action-result storage ↩1 ↩2 ↩3