Dependency graph and tasks
The dependency graph determines safe task order, cache reuse, and which applications are affected by a change.
The graph is the real architecture
Workspace manifests define nodes and edges. Build tools use those edges to run a package only after its dependencies, invalidate downstream work, and detect cycles.
Review graph changes explicitly. Adding one shared import can cause an expensive application to become affected by nearly every pull request.
Describe inputs, outputs, and dependencies
A task is cacheable only when its result is determined by declared inputs. Include source files, relevant configuration, environment variables, generated schemas, and dependency outputs. Declare build directories and generated files as outputs.
Tasks that access time, random values, undeclared network data, or mutable global state are not deterministic and should not pretend to be safely cacheable.
Run work in dependency order
Cache by content, not by hope
A cache key should represent task code, inputs, dependency outputs, command, toolchain, and meaningful environment. Identical keys should produce identical outputs on a laptop and in CI.
Remote caching lets teammates and CI reuse verified work. Protect cache integrity, avoid uploading secrets inside artifacts, and provide a way to bypass or inspect a suspicious hit.
Calculate affected work conservatively
Start with changed files, map them to owning projects, then walk downstream dependencies. Global configuration or lockfile changes may invalidate most of the graph.
Optimisation must not trade away correctness. Periodically run broader builds to detect missing graph edges and cache inputs.
Can you explain “Dependency graph and tasks” without reaching for the API reference?
Describe the main trade-off, one failure mode, and the decision you would make in a real project.