5.9.3 Key SkyValue Types
recommendedThe familiar Skyframe names—FileStateValue, FileValue, PackageValue,
ConfiguredTargetValue, ArtifactValue, and ActionExecutionValue—are best
read as families of computations in one dependency graph, not as stages in
one universal build pipeline. That distinction matters when you trace a rebuild:
an edge exists only when one concrete key requested another concrete key during
evaluation.1,2
Start at the filesystem boundary
FileStateValue records the result of inspecting one path with lstat() and,
for an existing file, enough additional state to detect a change. It is a leaf
family: it does not depend on another Skyframe node. FileValue adds the file
view that consumers usually need, including existence, type, resolved path, and
symlink resolution. A concrete FileValue depends on the corresponding
FileStateValue and may depend on more filesystem nodes while resolving path
components or symlinks.1
Directory membership uses a parallel branch, not merely FileValue.
DirectoryListingStateValue represents readdir(), while
DirectoryListingValue combines that listing with the directory's
FileValue. This branch is important for globs: adding a new matching file can
change a package even though no previously known source file changed.1
These types do not “apply .bazelignore.” Repository and package discovery
have additional computations and policies. A filesystem value answers a
question about a path. Whether Bazel considers that path part of a repository
or package-loading search is a separate graph concern.
Package and configured-target families describe analysis inputs
PackageValue represents a loaded package, including the result of evaluating
its BUILD file. It depends on the BUILD file's FileValue, loaded .bzl
computations and other package-loading inputs. Globs add directory-listing
dependencies. It does not normally depend on every source file named in the
package. Editing app/main.cc, for example, need not change the parsed rule
declaration that names main.cc.1,2
ConfiguredTargetValue represents analysis of one target under one
configuration. It carries the configured target's providers and the actions
registered by its analysis. Its neighborhood includes the package containing
the target, configured direct dependencies, configuration-related nodes,
toolchain resolution, configured attributes, and other analysis inputs. One
label can therefore participate in several ConfiguredTargetValue nodes, and
one package can feed many configured targets.1
The relationship is fan-in and fan-out, not a one-to-one progression:
BUILD-file and load inputs ──> PackageValue ──> many configured targets
▲ │
configuration and configured deps ─────────────────────┘
The exact edge set is implementation- and request-dependent. Use 5.9.1 Skyframe Data Model's rule—“A requested B”—instead of inferring an edge from the type names alone.
Artifacts bridge analysis and execution
The missing family in the supposed five-node chain is the artifact-value
computation. For a source artifact, ArtifactFunction derives file metadata
from the associated FileValue. Ordinary generated artifacts bypass
ArtifactFunction for memory efficiency: their metadata is accessed directly
from the corresponding ActionExecutionValue of the generating action. Tree
artifacts can require aggregation of child metadata, while runfiles trees also
take a specialized ArtifactFunction path. Do not assume every artifact key
follows the ordinary-file case. Conversely,
an ActionExecutionValue requests artifact keys for its inputs (plus other
execution dependencies), checks the action cache or executes the action, and
records output metadata.1,2
That creates alternating producer/consumer relationships in the execution subgraph:
source FileValue ──> source ArtifactValue ──> consuming ActionExecutionValue
producer ActionExecutionValue ──> output ArtifactValue ──> next action
The arrows above use result flow: a dependency's result points toward the
computation that consumes it. A raw Skyframe dependency edge uses the opposite
orientation—requester → requested key—so the corresponding stored edges are
ArtifactValue → FileValue and ActionExecutionValue → input ArtifactValue.
Always check a visualization's convention before following its arrows.
ConfiguredTargetValue registers actions during analysis, but it is not a
simple value dependency through which source bytes flow into action execution.
Current Bazel looks up an action from its action-owner data and requests the
action's input artifact keys during execution.2
ArtifactValue and ActionExecutionValue are not needed when execution does
not run. An analysis-only operation can populate package and configured-target
families without evaluating the corresponding action-execution subgraph.1
Trace rebuilds from observed edges, not a memorized chain
Suppose app/main.cc changes. A plausible local trace is:
- filesystem invalidation makes the source path's state and file nodes suspect.
- the source artifact metadata is re-evaluated.
- actions that consume that artifact become candidates for re-evaluation.
- changed outputs can affect artifact values consumed by downstream actions.
The package and configured-target nodes may remain reusable because the BUILD
declaration and analysis inputs did not change. By contrast, editing
app/BUILD.bazel can invalidate package loading and configured analysis, which
can change the registered action graph before execution is considered. Adding a
file matched by glob() enters through directory-listing nodes. These are three
different graph neighborhoods, despite all eventually contributing to a build.1
This model limits what you can conclude from “X rebuilt.” A type-level diagram
shows possible families of edges, not the retained keys and edges for this
invocation. It also does not prove that an action executed: cache lookup,
change pruning, command scope, configuration, action discovery, and execution
strategy still matter. 5.9.4 Incrementality Mechanism explains invalidation
and change pruning. Use aquery for the planned actions and execution logs or
profiles for evidence that an action actually ran.
For an internal investigation, record four facts rather than narrating a pipeline: the changed input, the exact key, the direct reverse dependencies in the retained graph, and the first node whose value or execution evidence actually differs. 5.6.8 Skyscope — Skyframe Visualizer can help inspect a small neighborhood, but internal class names and edges remain version-sensitive implementation details.
The key SkyValue types form interacting filesystem, loading/analysis, and
artifact/execution families. PackageValue does not generally depend on every
declared source file, and execution is connected through ArtifactValue. The
sequence FileStateValue → FileValue → PackageValue → ConfiguredTargetValue → ActionExecutionValue is therefore not a universal dependency chain.
To explain a rebuild, identify the changed concrete key and follow observed reverse dependencies. Separate BUILD or glob changes from source-content changes, and separate graph invalidation from proof that an action executed.
Check your understanding · 3 questions
1.A developer edits only the contents of a source file named in a rule. Which trace is the best starting hypothesis?
Select one answer
2.Match each SkyValue family to the question it primarily answers:
Drag each answer onto the matching prompt, or click an answer and then click a prompt
3.Evaluate these claims about using SkyValue types to explain rebuilds.
Choose True or False for each sentence
Footnotes
-
Skyframe — mapping of filesystem, package, configured-target, artifact, and action-execution families ↩1 ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8
-
Bazel upstream source —
PackageFunction,ConfiguredTargetFunction,ArtifactFunction, andActionExecutionFunctiondependency requests at commite9e7d623a3d2d41803564b03a2e051a9f1c912d9(verified 18 July 2026) ↩1 ↩2 ↩3 ↩4