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 is the server’s in-memory graph
A warm server reuses graph state. An edit invalidates only the work that depends on it.
WARM SERVER
The graph survives the next command
Same long-lived process and output base
build cquery build

Skyframe nodes stay in memory. Later build-style commands reuse loading and analysis where inputs still match.

COLD START
The in-memory graph is gone
Shutdown, idle timeout, or startup-option restart
shutdown build

A new server rebuilds Skyframe from scratch. Disk and remote caches can still reuse action outputs.

one source file changes
INVALIDATION & PRUNING
Only the dependent chain is marked dirty
Unrelated work stays clean. An unchanged result stops the update.
Affected branch
lib.cc Changed file input
compile lib Invalidated and recomputed
//app:binary Stays clean if library output unchanged
Unrelated branch
util.cc Does not depend on the changed file
compile util No invalidation from this edit
Change pruning
If the recomputed node’s SkyValue equals the previous one, Bazel does not dirty dependents above it — work stops there.
Skyframe remembers dependency-linked state in the server, so one edit means local invalidation and, when outputs match, no update beyond that point.

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

extra

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

key takeaway

Skyframe is Bazel's in-memory record of the build. It turns "one file changed" into "recompute only the affected chain," and it explains why a warm server feels fast even before remote or disk caches enter the picture.1,2,3,5

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

Skyframe tracks only source file changes. BUILD file edits require a clean build to take effect.
Skyframe lives in server memory, so a 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

0 of 3 answered

Footnotes

  1. Skyframe — immutable node model, evaluation graph, bottom-up invalidation, and change pruning 1 2 3 4 5 6 7 8

  2. Client/server implementation — long-lived server caching of build metadata across invocations, idle shutdown, and restart behavior 1 2 3 4

  3. 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

  4. Trimming the Build Tree with Bazel — upward transitive closure invalidation and stopping when a rebuilt dependency's output is unchanged 1 2

  5. 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