Free tools Windows power users keep installed
One-click scans. No signup required.
If your Docker CI build repeatedly downloads dependencies or recompiles unchanged code, BuildKit cache mounts can reduce that repeated work—but they do not automatically persist on every CI runner. The key distinction: BuildKit’s instruction cache can reuse completed build steps, while a RUN --mount=type=cache directory holds tool-specific data such as compiler or package-manager caches. On a persistent builder, that directory may survive between builds. On an ephemeral GitHub-hosted runner, GitHub Actions cache export does not preserve cache-mount contents by default, so you need a separate persistence strategy.
What a BuildKit cache mount does
A cache mount adds a directory to a Dockerfile RUN instruction. A compiler or package manager can reuse files stored there on a later execution of that instruction. For example, Go can reuse its build cache at /root/.cache/go-build:
As an Amazon Associate I earn from qualifying purchases.
# syntax=docker/dockerfile:1
FROM golang:1.24 AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN --mount=type=cache,target=/root/.cache/go-build go build -o /out/app .
The Go version and project commands here are illustrative; use the version and build steps your project requires. Docker’s documented Go example uses the same cache-mount target. The cache mount is available only for the mounted RUN; its contents are not committed into the resulting image layer. That keeps build-only data out of the image while letting the tool reuse it on the same builder.
Docker’s rule is important: “Cache mounts should only be used for better performance.” The build must still succeed if the mounted directory is empty or has been removed, for example by builder garbage collection. Do not store required outputs or correctness-critical inputs only in a cache mount. Dockerfile reference: RUN –mount
#1 Best Overall
Layer cache and cache mounts solve different problems
BuildKit’s ordinary instruction cache can reuse a previously completed instruction when its inputs and relevant build configuration still match. Good Dockerfile ordering helps: copy dependency manifests and install dependencies before copying frequently changing application source. When an instruction must run again, a package-manager or compiler cache mount can still let the tool reuse downloads or compiled artifacts from its prior runs.
| Cache | What it reuses | How to persist or export it |
|---|---|---|
| BuildKit instruction/layer cache | Results of completed build steps whose inputs still match | Configure BuildKit cache import/export, such as cache-from and cache-to. |
| Cache mount | Tool-managed files in a directory mounted during a RUN, such as downloaded packages or compiler artifacts |
Persists on a builder between invocations when that builder retains it; GitHub Actions cache export does not preserve it by default. |
These mechanisms complement one another. External layer-cache export does not, by itself, mean that the cache-mount directory is saved. Docker’s CLI documentation describes the Buildx cache options; its GitHub Actions cache guide documents the backend and setup. Buildx build reference · GitHub Actions cache backend
Choose persistence based on your CI builder
Persistent builder
If successive jobs use the same builder and its storage is retained, cache-mount contents can persist between build invocations. This is the simplest route for mount data, but it depends on the builder’s lifecycle and cleanup policy. A replacement, reset, or garbage collection can remove the data; correctness must not depend on it.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Rank #2
Ephemeral GitHub-hosted runner
A fresh runner generally means a fresh builder, so the mount data is not simply there for the next job. Docker documents a workaround using reproducible-containers/buildkit-cache-dance: it extracts cache-mount contents before the build and injects them for the build. Docker’s example mounts Go modules at /go/pkg/mod and the Go build cache at /root/.cache/go-build. The example pins the action to commit 4b2444fec0c0fb9dbf175a96c094720a692ef810 and labels it v2.1.4; verify the project’s current instructions and version-sensitive configuration before adopting it. Docker: Cache management with GitHub Actions
Regardless of whether you preserve mounts, configure ordinary BuildKit cache import/export separately if you want reusable build-step results across ephemeral runs. Docker’s GitHub Actions examples use cache-from: type=gha and cache-to: type=gha,mode=max. The GitHub Actions backend is experimental, and its availability depends on Buildx configuration and GitHub’s cache limits. In particular, Docker notes that the default docker driver requires the containerd image store to be enabled. Check the current backend documentation for your runner and Buildx setup. GitHub Actions cache backend
Registry-backed cache
Docker also documents exporting BuildKit cache to a registry reference separate from the image, using registry cache import/export with mode=max. Inline cache export is simpler but supports only min mode. These are options for BuildKit’s external cache; they do not automatically save cache-mount directories. Docker cache-management examples
Rank #3
Configure mount sharing for concurrent builds
The optional id identifies a mount; if omitted, it defaults to the target path. Use distinct IDs when different tools or projects need separate caches. The sharing setting controls how concurrent builds access a mount:
shared: concurrent writers may use the mount.private: concurrent builds receive separate mount instances.locked: a second build waits until the current writer releases the mount.
Choose according to the cache tool’s concurrency requirements, not just convenience. Docker’s apt example uses sharing=locked because apt needs exclusive access to its data. It also adjusts apt cleanup behavior so downloaded packages remain available to the cache. Do not copy that apt-specific setup blindly for a different package manager. Dockerfile reference: cache mounts and apt example
Example: cache apt data safely
For Debian-based images, Docker’s example retains apt’s package data and serializes access with locked mounts. The relevant pattern is:
# syntax=docker/dockerfile:1
FROM debian:bookworm-slim
RUN rm -f /etc/apt/apt.conf.d/docker-clean
&& echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked
--mount=type=cache,target=/var/lib/apt,sharing=locked
apt-get update && apt-get install -y --no-install-recommends curl
This is Docker’s documented apt pattern, not a universal recipe for every Debian-family image or package setup. Keep the package index refresh and installation in the same instruction, and adapt package names and image choice to your actual build.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Handle GitHub Actions cache permissions deliberately
Some workflow events, including issue_comment and pull_request_target in the default-branch context, have read-only cache access by default. A workflow can therefore import cache successfully but fail when it tries to export. For such a workflow, retain cache-from when useful and omit cache-to; populate or update the cache from a workflow with write access, such as an appropriate default-branch push workflow.
Do not broaden cache write permissions casually for untrusted workflows. Docker warns that granting write access can create cache-poisoning risk. Check the current GitHub and Docker guidance for event behavior and permissions before changing workflow access. Docker: GitHub workflow permissions
Best Value
Diagnose why the build is still slow
- Every step runs again: inspect Dockerfile instruction ordering and build inputs, then confirm the workflow is importing and exporting the external BuildKit cache.
- Dependency or compiler work repeats inside a rerun step: add a cache mount at the tool’s actual cache directory, then verify that the builder persists or that your CI setup separately preserves the mount contents.
- Works locally but not in GitHub Actions: local reuse may come from a persistent builder. GitHub Actions cache export alone does not preserve mount directories; use a persistent builder or Docker’s documented extraction/injection workaround.
- Cache import succeeds but export fails: inspect the triggering event and workflow permissions. A read-only event should not be expected to write the cache.
- Concurrent builds corrupt or block a tool cache: review the tool’s concurrency needs and select
shared,private, orlockedaccordingly.
Docker’s cache-backend documentation also records version-sensitive requirements, including a migration from GitHub Cache API v1 to v2 and minimum versions for some self-managed environments. Self-hosted runners should be checked against the current documentation rather than relying on an old workflow snippet. GitHub Actions cache backend
What to expect from a 15-minute build
“15 minutes” is a scenario, not a generally established Docker CI benchmark. Neither the cited Docker documentation nor this configuration alone establishes how much time a particular project will save. Measure your own workflow before and after: record total job time and, separately, whether dependency downloads, compilation, or other steps are repeated. Cache mounts help only when a rerun tool can reuse valid files and those files are available on the builder; layer caching helps when a completed instruction remains reusable. The right setup may need both.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errors




