Remote Task Cache
also called Shared Task Cache, Content-Addressed Build Cache
A shared store of task outputs keyed by a hash of every input, so a build test or lint run already performed anywhere is replayed instead of repeated - and whose hit rate is a direct measure of how deterministic a repository's tasks are.
A monorepo's first scaling move is to run only the tasks a change affects. The second is to notice that most of those tasks redo work somebody already did - the same library, compiler and source bytes, rebuilt because the package sits downstream of an unrelated change or because the author rebased.
A remote task cache closes the gap. Each task declares its inputs - source files, dependency outputs, toolchain versions, environment variables, its own configuration - and the runner hashes them into a key. A key already in the shared store restores the recorded outputs and reports a hit; otherwise the task runs and writes its outputs back under that key.
The interesting part is not the storage. It is that the hit rate measures determinism, and most teams find theirs far below what they assumed.
Why it matters
Take 12 applications and 28 libraries, a 95-minute full fan-out run, a 14-minute affected run and about 350 CI runs a week - 140 pull requests at roughly 2.5 pushes each. Affected-graph scoping moves the weekly bill from about 33,000 runner-minutes to about 7,700. A cache hitting 60-70% of tasks moves it to roughly 3,000.
At hosted-runner list prices on the order of a cent a minute in 2025 that is $17k a year against under $2k, which is not the argument. The argument is wall clock: 14 minutes of feedback instead of 95 changes how many review cycles fit into a day.
Implementation patterns
- Hash the whole input set, including the toolchain. A key built from source files alone returns outputs compiled by last month's compiler.
- Declare inputs narrowly. A glob of
**/*makes every task depend on the README, so a documentation commit invalidates the repository. - Split read and write credentials. Pull requests read; only trusted CI on the protected branch writes, which is what stops a fork publishing entries the main branch later trusts.
- Publish hit rate per task type, because type-checking, linting and unit tests cache well while anything touching the network or the clock does not.
Industry example
The affected-graph-plus-remote-cache design has been the default in this class of frontend build tool since around 2020, which is why hosted cache services are sold beside them.
The instructive archetype is a platform team with roughly 40 packages that adopts one, sees a 70% hit rate in week one, and finds six months later that its steady state in production is near 20%. The causes are always the same: a build stamp containing the git SHA, a test reading the current date, a toolchain resolved at install time, a glob reaching the repository root. None are cache problems; they are non-determinism the cache made visible.
Failure scenarios
- A poisoned entry. If untrusted CI can write, a pull request can publish outputs under a key the protected branch later reads, and the artefact looks legitimate.
- A stale hit after a toolchain upgrade left out of the key: correct for the old compiler, silently wrong for the new one.
- A non-hermetic test cached green, because it passed thanks to a leftover file and that pass is now permanent.
Trade-offs
| Choose | Gains | Pays |
|---|---|---|
| Remote task cache | 60-70% fewer executed tasks | a store to secure; input declarations to maintain |
| Scoping only | most of the saving for configuration alone | repeats work after every rebase |
| Run everything | no cache-correctness risk | full-run wall clock per push |
Scoping is configuration; caching is infrastructure - and infrastructure brings a new class of incident in which the build lies to you.
When not to use it
Skip it while a full run is under roughly 10 minutes, or below about five packages: there is not enough repeated work to recover and the failure modes cost more than the wait. Skip it for genuinely non-deterministic tasks rather than forcing them - release stamping, publishing, anything calling a live service.
Skip it too when the diagnosis is wrong. If more than roughly 30% of pull requests touch a hub package, the bill comes from fan-in rather than repetition, and no cache helps because the affected set genuinely is everything. The fix is finer granularity: per-component entry points and type-only changes that skip runtime suites.
Interview question
Q: Your monorepo has affected-graph scoping and a remote cache, and CI is still slow. How do you establish whether the problem is fan-in, hit rate or runner capacity, and what changes for each?
What a strong answer covers: affected-set size per pull request to measure hub share; hit rate per task type rather than overall; input manifests inspected for SHAs, clocks and wide globs; capacity last, because queueing shows as wait time rather than run time; and a different fix per cause - granularity, input hygiene, then runners.
Quick check
Quiz: A team's cache reports a 20% hit rate. Name three input declarations that would cause it. Answer: a build stamp containing the git SHA, a toolchain resolved at install time instead of pinned, and an input glob wide enough to include the repository root.
Flashcard: What does a remote task cache's hit rate measure? — How deterministic the tasks are. Clock reads, git SHAs, unpinned toolchains and wide globs make hits impossible; a clean repository steady-states near 60-70%.