Skip to Content
Cut Rebuild Time With a BuildKit Cache Mount
Advanced
0 likes
Tutorials

Cut Rebuild Time With a BuildKit Cache Mount

Add a BuildKit cache mount to pip install so a changed requirements file downloads only the new packages. After this, a dependency change no longer means downloading everything again.

Every time requirements.txt changes, pip downloads every package again, including the big ones that did not change. A BuildKit cache mount keeps pip's download cache between builds without putting it in the image. This page is the short version of the BuildKit lesson in the Docker Advanced course. I ran it on Docker Desktop 4.85.0 (Engine 29.6.2) with python:3.14-alpine, on a fresh builder so the first build starts with an empty cache.

Before you start

Check that your Dockerfile already copies the dependency list before the rest of the code. If COPY . . comes before pip install, fix that first. A cache mount does not help with code edits; the layer order does.

The Dockerfile

numpy==2.5.4
import numpy
print("numpy", numpy.__version__)
FROM python:3.14-alpine
WORKDIR /app
COPY requirements.txt .
RUN --mount=type=cache,target=/root/.cache/pip \
    pip install --root-user-action=ignore -r requirements.txt
COPY app.py .
CMD ["python", "app.py"]

The only new part is --mount=type=cache,target=/root/.cache/pip on the RUN line. /root/.cache/pip is where pip keeps downloads when it runs as root. Do not add --no-cache-dir to that pip install; it would tell pip to ignore the cache you just mounted.

First build

Set-Location mount-demo
$t = Measure-Command { $log = docker build --progress=plain -t mount-demo . 2>&1 | ForEach-Object { "$_" } }
$log | Select-String "Downloading numpy|Using cached numpy" | ForEach-Object { $_.Line -replace '^#\d+ \d+\.\d+ +', '' }
"build took {0:N0} s" -f $t.TotalSeconds
docker run --rm mount-demo
Downloading numpy-2.5.4-cp314-cp314-musllinux_1_2_x86_64.whl.metadata (6.6 kB)
Downloading numpy-2.5.4-cp314-cp314-musllinux_1_2_x86_64.whl (18.5 MB)
build took 22 s
numpy 2.5.4

Change a dependency and build again

Add a second package. The install step has to run again, because its input changed.

Add-Content requirements.txt "flask==3.1.3"
$t = Measure-Command { $log = docker build --progress=plain -t mount-demo . 2>&1 | ForEach-Object { "$_" } }
$log | Select-String "Downloading numpy|Using cached numpy" | ForEach-Object { $_.Line -replace '^#\d+ \d+\.\d+ +', '' }
"build took {0:N0} s" -f $t.TotalSeconds
Using cached numpy-2.5.4-cp314-cp314-musllinux_1_2_x86_64.whl.metadata (6.6 kB)
Using cached numpy-2.5.4-cp314-cp314-musllinux_1_2_x86_64.whl (18.5 MB)
build took 15 s

pip took numpy, an 18 MB download, from the cache and downloaded only Flask and its dependencies. The times will be different on your machine and your connection. What matters is the Using cached line.

Check the cache is not in the image

docker run --rm mount-demo sh -c "ls /root/.cache/pip 2>&1 || true"
No such file or directory

The cache lives in the builder, not in the image. Pushing the image does not push the cache.

Other package managers

Use the cache folder of your tool as the target:

Tooltarget
pip (root)/root/.cache/pip
npm/root/.npm
Go modules and build cache/go/pkg/mod and /root/.cache/go-build
apk/var/cache/apk (add sharing=locked)

I only ran the pip version.

If it does not work

  • Every build still downloads everything: you are probably on a fresh CI runner or a new builder, which starts empty. The cache is per builder.
  • Using cached never shows up: check that pip does not run as another user with USER before the install. A non-root user keeps its cache in its own home folder, so the target must match.
  • The image is missing packages: you installed into the cache folder instead of from it. Nothing in a cache mount ends up in the image.

💡 Tip: To empty the build cache of the default builder, docker builder prune removes cache that nothing uses. Read what it says before you confirm, because it is not limited to one project.

Related course: Docker Advanced.

About

Add a BuildKit cache mount to pip install so a changed requirements file downloads only the new packages. After this, a dependency change no longer means downloading everything again.

Responsible
Jay P
Last Update
08/01/2026
Reading Time
4 min
Was this helpful?
​ 0 ​ 0

Comments (0)

Sign in to comment

No comments yet.