The physics of Docker build caching: three caches, one wave
A measured breakdown of Docker's three build caches — layer chain, mount cache, image store — and when each caching strategy actually helps.
Docker build caching is often treated as a single mechanism, but it's actually at least three separate systems — the layer chain, mount caches, and the image store — each with distinct lifetimes and invalidation rules. A change to a Dockerfile triggers an 'invalidation wave' that propagates from the changed layer to the end of the chain, and which cache actually matters depends entirely on the shape of the build.
A benchmark spanning 18 scenarios across Go, Python, Rust, Node, Java, and Bazel shows that manifest-first layer ordering (copying dependency files before source code) cuts source-change build times by 3x to 24x, with the payoff scaling directly with the cost of the protected step. The study also shows that export/import cache backends (GHA, registry, etc.) don't carry mount-cache contents like compiler or package-manager state — meaning they can sometimes be slower than using no cache at all when the win actually lived in the mount.
The practical takeaway for engineers: a typical CI build is a source-change, not a cold build. Ordering Dockerfiles around change frequency and knowing whether your speedup lives in the layer chain or in mount caches is what determines whether a given caching setup helps, does nothing, or actively hurts.