What does a shared remote build cache give a CI fleet that a per-runner local cache cannot, and what must be true of a build for a cross-machine cache hit to be safe?
answer
- hash of declared inputs, not of a directory
- survives ephemeral runners and crosses branches
- output must be a pure function of inputs
- absolute paths and timestamps break it
- CI writes, everyone else reads
basics
~20 sA remote cache is content-addressed by a hash of a task's declared inputs, so any machine that computes the same hash reuses the output — across ephemeral runners, branches and developer laptops. It is safe only if nothing outside those declared inputs affects the output.
solid answer
~50 sA local cache dies with the runner, which on an ephemeral fleet means it barely exists. A remote build cache moves the store off the machine and keys entries by a hash of a task's declared inputs — source files, tool versions, compiler flags, environment, upstream outputs — so any machine computing the same hash downloads the result instead of recomputing it. That is what makes reuse possible across runners, across branches, and often between CI and developer machines. The precondition is determinism with respect to the declared inputs: given the same inputs, the task must produce the same output. Builds break that constantly — absolute paths baked into outputs, embedded timestamps or hostnames, undeclared environment variables, network fetches during the build, nondeterministic ordering in generated code. Each of those means a hit returns something subtly different from what the machine would have built. And because a hit is executed, write access is a trust boundary: CI writes, everyone else reads.
go deeper
Know that a local cache disappears with the runner, and that a remote cache stores results centrally so a different machine can reuse them.
Explain the keying: a hash over a task's declared inputs — sources, tool versions, flags, upstream outputs — and why that is what allows reuse across machines and branches.
Show that adoption is a build-determinism project: name the hermeticity violations, describe how you would verify outputs against a cache-disabled run, and set the read/write trust asymmetry.
Own the org-level decision — the cost of making builds hermetic against the fleet-wide time saved, cache sizing, region placement and egress, and the governance of who may write entries every team consumes.
## What the remote cache actually changes A local build cache lives on one machine's disk. On a fleet of ephemeral runners — the norm for isolation reasons — that machine is destroyed after every job, so the cache's hit rate is close to zero by construction. Even on persistent runners, each machine warms independently, so N runners means N cold starts and no sharing between them. A remote build cache inverts the arrangement. The build tool computes, for each unit of work it is about to do, a hash over that unit's **declared inputs**: the source files it reads, the toolchain version, the compiler flags, the relevant environment variables, and the hashes of the outputs it depends on. That hash is the key. If the remote store has an entry, the tool downloads the output and skips the work. If not, it does the work and uploads the result. The consequences are the interesting part: - Reuse survives the runner. A fresh ephemeral machine can be as fast as a warm one. - Reuse crosses branches. A pull request that touches one module reuses everything the default branch already built. - Reuse crosses people. Developers can pull CI's outputs instead of building locally, if you let them read. - Reuse is per task, not per job. Nothing needs to match wholesale; the unchanged 90% of the graph is skipped. Build tools with this capability include Gradle's build cache and Bazel's remote cache; for C and C++ compilation, `ccache` and `sccache` occupy the same niche at a lower level of granularity. ## The precondition: determinism against declared inputs The cache promises that the downloaded output equals what the machine would have produced. That promise holds only if the task is a pure function of its declared inputs. Every common violation is a source of silently wrong builds: - **Absolute paths baked into outputs.** Debug info, generated manifests, virtual-environment shebangs and compiled bytecode frequently embed the build directory. An entry produced under `/home/runner-07/work` is then not valid on a machine using a different path. - **Timestamps and hostnames.** A build that stamps the current time or the builder's hostname into an artifact produces a different output for identical inputs, which both breaks verification and pollutes the store. - **Undeclared environment.** A variable the task reads but the key does not include: locale, timezone, a feature flag, a proxy setting. - **Network access during the task.** Anything fetched at build time can change between the entry being written and being reused, and the fetch is invisible to the key. - **Nondeterministic ordering.** Map iteration order in a code generator, parallel output concatenation, archive member ordering without a sorted-entry setting. So the honest answer to "can we turn on the remote cache?" is usually "after we make the build hermetic," not "yes, tomorrow." Tools help — several offer a mode that runs a task twice and compares outputs — and a periodic cache-disabled build compared byte-for-byte against a cached one is the low-tech version of the same check. ## Trust: writes are an execution path A cache hit means executing or shipping bytes someone else produced. That makes write access a security boundary, not an operational convenience. The standard arrangement is asymmetric: trusted CI jobs on trusted refs write; developers and pull-request builds read only. Authentication is required in both directions, and it is worth remembering that a wrong entry does not announce itself — it is discovered when something behaves oddly in production, at which point rotating the cache namespace and rebuilding is the response. ## When a hit is not a win A remote hit costs a network round trip and a download. It only pays when fetching beats recomputing. Large outputs over a constrained link — or a runner fleet in a different region from the cache — can genuinely be slower than building locally, especially for fast tasks. Most implementations expose thresholds so small or cheap tasks are not cached at all. Also budget for the store itself: total size, eviction policy, and egress cost if the cache and the runners sit in different networks. ## What to say in an interview Lead with the key insight — the cache is content-addressed on declared inputs, so correctness is a property of the *build*, not of the cache — then name the concrete hermeticity violations, then the trust asymmetry, then the network-cost caveat. Candidates who describe it purely as "a faster cache in the cloud" miss that adopting one is mostly a build-determinism project.
- Name the hermeticity violations you would look for before enabling a remote build cache.Absolute paths embedded in outputs, timestamps and hostnames stamped into artifacts, environment variables the task reads but the key does not include, network fetches performed during the build, and nondeterministic ordering in generated files or archives. Each produces a different output for identical declared inputs, which is exactly the condition the cache assumes cannot happen.
- Who should be allowed to write to the shared cache, and why does it matter?Only trusted CI jobs on trusted refs. A cache hit means running or shipping bytes someone else produced, so write access is a code-execution path into every consumer of the cache. Developers and pull-request builds get read access, which delivers most of the speed benefit with none of the trust exposure.
- When would a remote cache hit actually be slower than rebuilding?When downloading the output costs more than recomputing it — large artifacts over a constrained or cross-region link, or tasks that take a second to run anyway. Most implementations let you set a minimum task duration or output size for caching, and the cache and runners should sit close together on the network.
- How do you verify that a cached output equals what the machine would have built?Run the build periodically with the cache disabled and compare the outputs byte for byte against a cached run. Some tools also offer a repeat-execution mode that runs a task twice and reports differing outputs. Any mismatch names a specific undeclared input, which is the actionable form of the finding.
saying these in an interview costs you the question
- Calls it just a bigger cache in the cloud
- Ignores build determinism as a precondition
- Lets every developer machine write cache entries
- Assumes a cache hit is always faster than rebuilding
- Confuses it with caching container image layers