5.9.1 Skyframe Data Model
recommendedSkyframe is the evaluator behind Bazel's incremental work. Its smallest useful
model is a memoized computation: ask for a SkyKey, run the SkyFunction
selected by that key's function name if no reusable result is available, record
every requested dependency, and associate the resulting SkyValue with the
key. This is an implementation model for interpreting Bazel, not a public API
for BUILD or Starlark authors.1,2
This refines the first-response model in 2.4.1 Skyframe & Incrementality. Later infrastructure work can deliberately prune or preserve parts of this state; 6.6.9 Bottleneck-Driven Optimization covers those operational designs without changing the node model developed here.
Read the three names as three different roles
A SkyKey identifies a computation. In current Bazel source it is
effectively a pair of a SkyFunctionName and an argument. The function name
selects the computation family. The argument distinguishes one request in that
family. Keys are designed to be compact, stable map keys because a Bazel server
can retain very many of them.1,2
A SkyFunction implements a computation family. Skyframe dispatches a key
to the registered function for its function name and calls compute(key, env).
The function may ask the environment for other keys. Those requests create the
dependency edges that let Skyframe schedule work and later decide what may be
stale. 5.9.2 Evaluation Model follows the request-and-restart protocol in
detail.1,3
A SkyValue is the completed result returned for a key. The key is the
identity of the request. The value is its data. A value is therefore not the
graph node's identity, and it is misleading to use “node” to mean only the
Java value object. In diagnostic discussions, a Skyframe node is best read as
the evaluator's entry for a SkyKey, together with its result, dependency
edges, error and evaluation state.1,2
That distinction prevents a common category error. Two keys in the same function family can produce two different values, while re-evaluating one key can produce a value equal to its previous value. The latter fact is what makes change pruning possible. 5.9.4 Incrementality Mechanism develops that mechanism.
Trace one request instead of memorizing class names
Suppose Bazel needs the parsed package //app. The names below are conceptual,
not promises about bazel dump syntax or Java class names:
requested key: (PACKAGE, //app)
function: package-loading computation
dependencies: keys for BUILD-file and directory state
result: parsed package data
The evaluator first uses the key's function name to select the package-loading function. During computation, that function requests keys for the filesystem facts it needs. Their returned values become inputs to the package result, and the evaluator records edges from the package key to those dependency keys. This one trace contains the whole data model: key, dispatched function, dependency keys and values, then the value for the original key.1
Real diagnostic output may show families such as FILE_STATE, PACKAGE,
CONFIGURED_TARGET, or ACTION_EXECUTION, with version-dependent spelling and
arguments. Treat examples like FILECONTENTS:/tmp/foo from older documentation
as illustrations of function family plus argument, not as a grammar to parse
in production automation. Current SkyKey.getCanonicalName() also derives a
string from functionName() and argument(), but both the internal types and
dump representations remain implementation details.1,2
The graph is discovered during evaluation
An edge A → B means computing the value for key A requested the value for key
B. It does not mean that A is a BUILD target depending on target B, nor that an
action for A ran before an action for B. One retained Skyframe graph crosses
filesystem, package, configured-target, artifact, action-execution, and other
internal computations. This is why a raw dump or Skyscope view contains more
node families than query, cquery, or aquery.1
For a successful evaluation, those dependency edges form a directed acyclic graph: a value cannot be completed through a dependency chain that leads back to itself. But “the graph is a DAG” does not mean Skyframe can assume that requested dependencies are always acyclic. Real evaluation includes cycle detection and reports cycles as errors. The DAG is the usable dependency structure of completed work. Cycle handling is part of making the evaluator robust.3
Also avoid picturing a fixed graph declared before the build. A function can discover dependencies while it computes—for example, resolving a symlink can reveal another filesystem key. Skyframe records the dependencies actually requested for that evaluation. The graph retained by the long-lived server is therefore internal state shaped by commands and invalidation, not a single canonical representation of the workspace.1
“Immutable” is a correctness contract, not an interface keyword
Skyframe documentation describes keys and values as immutable. The practical reason is straightforward: keys serve as hash-map identities, and cached values are compared and reused. Mutating either after publication would make lookup, dependency tracking, or equality-based reasoning unreliable.1
Do not over-read that statement as a guarantee enforced by the Java type
system. SkyKey and SkyValue are interfaces. Their current declarations do
not mechanically make every implementation immutable. Individual
implementations must honor the contract, and some evaluator bookkeeping is
necessarily mutable. In particular, the node entry around a key/value records
evaluation and invalidation state even though the published key and completed
value should be treated as immutable.2
The same precision matters for SkyFunction. “Deterministic and
side-effect-free” is a useful ideal for a hermetic computation, but it is not a
universal description of Bazel's implementations. Current source distinguishes
hermetic, semi-hermetic, and non-hermetic function names. The official model
also permits carefully managed outward effects such as writing outputs, while
warning that unregistered reads can break incremental correctness. The safe
consulting claim is: every input that can affect a result must be represented by
a tracked dependency or an explicit non-hermetic invalidation mechanism.1,2
Use the model to sharpen an investigation
When an internal graph appears in a stack trace, dump, or visualization, ask four questions in order:
- What exact
SkyKeyidentifies this node—both its function family and its argument? - Which
SkyFunctionfamily computes it? - Which dependency keys did that computation request, and what does each edge mean at this graph layer?
- What completed
SkyValue, error, or incomplete evaluation state is retained for the key?
This vocabulary narrows hypotheses without pretending the internals are stable
observability APIs. Use 5.6.8 Skyscope — Skyframe Visualizer or a Skyframe dump to find an
internal neighborhood, then return to supported tools: query for declared
targets, cquery for configured targets, aquery for actions, and profiles or
execution logs for what actually ran.
A Skyframe computation is identified by a compact SkyKey, dispatched to the
SkyFunction family named by that key, connected to every dependency key the
function requests, and completed with a SkyValue. Read a graph node as the
evaluator entry keyed by the SkyKey, not as the value object or a BUILD target.
The completed dependency structure is acyclic, but Skyframe still detects cycles during evaluation. Keys and completed values follow an immutability contract, while evaluator state remains mutable. Functions aim for tracked, deterministic inputs but are not universally side-effect-free. Internal key names and dump strings are diagnostic clues, not stable public APIs.
Check your understanding · 3 questions
1.Match each Skyframe concept to its role:
Drag each answer onto the matching prompt, or click an answer and then click a prompt
2.What does a Skyframe dependency edge A → B mean?
Select one answer
3.Which cautions apply when interpreting the Skyframe data model?
Select all that apply
Footnotes
-
Skyframe — data model, dependency discovery, DAG semantics, effects, and mapping to Bazel computations ↩1 ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10
-
Bazel upstream source — current
SkyKey,SkyValue,SkyFunction, andSkyFunctionNameinterface contracts (verified 18 July 2026) ↩1 ↩2 ↩3 ↩4 ↩5 ↩6 -
Empyrean Evaluation — memoization model, cycle detection, and the production evaluator's additional responsibilities ↩1 ↩2