Docker caches image build results to accelerate subsequent rebuilds. While this mechanism is generally reliable, sometimes you’ll want to rebuild an image without using the cache. This could be to diagnose issues or check the complete build procedure will be reproducible in a clean environment.
In this article, you’ll learn how to achieve a fresh build without manually deleting the cache. You’ll also see how to pull updated base images so your build matches the output that a new Docker installation would produce.
How the Cache Works
Here’s a simple Dockerfile:
FROM alpine:latest COPY 1.txt /1.txt COPY 2.txt /2.txt
Populate the sample files in your working directory and build the image:
$ echo 1 > 1.txt $ echo 2 > 2.txt $ docker build -t demo:latest .
The output will look similar to this:
Sending build context to Docker daemon 5.12kB Step 1/3 : FROM alpine:latest ---> 9c6f07244728 Step 2/3 : COPY 1.txt /1.txt ---> db61ff73c0b5 Step 3/3 : COPY 2.txt /2.txt ---> f1129e47fc12 Successfully built f1129e47fc12 Successfully tagged demo:latest
2.txt and then rebuild the image:
$ echo two > 2.txt $ docker build -t demo:latest . Sending build context to Docker daemon 5.12kB Step 1/3 : FROM alpine:latest ---> 9c6f07244728 Step 2/3 : COPY 1.txt /1.txt ---> Using cache ---> db61ff73c0b5 Step 3/3 : COPY 2.txt /2.txt ---> 75ba7d786049 Successfully built 75ba7d786049 Successfully tagged demo:latest
The second build stage shows
Using cache because the contents of
1.txt haven’t changed. The intermediate layer with ID
db61ff73c0b5 gets reused for the new build.
Disabling the Cache
You can disable use of the intermediate layer cache by including the
--no-cache flag when you run
$ echo second > 2.txt $ docker build --no-cache -t demo:latest . Sending build context to Docker daemon 5.12kB Step 1/3 : FROM alpine:latest ---> 9c6f07244728 Step 2/3 : COPY 1.txt /1.txt ---> 1590b2407dd4 Step 3/3 : COPY 2.txt /2.txt ---> afb31630ce32 Successfully built afb31630ce32 Successfully tagged demo:latest
This time a new image layer, ID
1590b2407dd4, has been created by the second build stage, even though
1.txt remains unmodified.
You can use the
--no-cache flag to force a rebuild when you suspect the cache is stale or you want to start from scratch. Build performance will be reduced because Docker will need to recreate every layer.
Pulling Updated Base Images
Another form of caching concerns the base images which your Dockerfile references in its
FROM instructions. The example image above uses
alpine:latest as its base. Docker won’t automatically pull an updated version of
alpine:latest, unless the image doesn’t already exist on your host.
This means the first build of a Dockerfile will pull down the base images you need, as long as you don’t already have them. Subsequent rebuilds won’t refresh the images so you could be building on an outdated base. Building the image on a different Docker host might not produce the same output if that host pulls a newer version of the base.
You can force Docker to check for updated base images at build time by adding the
--pull flag to your
docker build command. This is separate to
--pull will retrieve the image tag’s manifest from its registry and compare it to the version on your machine. The new image will be pulled from the registry when there’s a discrepancy in the manifests.
$ docker build --no-cache --pull -t demo:latest . Sending build context to Docker daemon 5.12kB Step 1/3 : FROM alpine:latest latest: Pulling from library/alpine Digest: sha256:bc41182d7ef5ffc53a40b044e725193bc10142a1243f395ee852a8d9730fc2ad Status: Image is up to date for alpine:latest ---> 9c6f07244728 Step 2/3 : COPY 1.txt /1.txt ---> 4fee970dfaab Step 3/3 : COPY 2.txt /2.txt ---> 60d2e3fff0fb Successfully built 60d2e3fff0fb Successfully tagged demo:latest
The above example shows how the build output changes when the
--pull flag is used. Docker tries to pull the Alpine base image, even though it’s already on the machine from the earlier example builds. The image digest (SHA) is printed to the terminal. In this case the digest is unchanged from the local version so Docker reports that the image is already up to date.
--pull flags can be used independently or in combination. Adding them both gives you the cleanest slate for starting your build, forcing Docker to check for updated base images and disregard any previously created layers. It’s equivalent to running the build on a newly installed Docker host.
Using Docker Compose
Docker Compose supports both the
--pull flags too. They have the same effect as their
docker build counterparts.
# Compose v2 $ docker compose build --no-cache --pull # Compose v1 $ docker-compose build --no-cache --pull
Cleaning the Build Cache
You can clean the build cache to guarantee it’s disused. This also helps to free up excess disk space consumed by cached build layers.
docker builder prune command to empty your cache. It only works when you’re building images with the modern BuildKit build engine.
$ docker builder prune
Running the command without arguments only removes the dangling build cache. This relates to caches that relate to images no longer present on your host. Add the
-a flag to completely empty the cache, including layers that are used by images:
$ docker builder prune -a
Pruning also accepts a
--filter flag that can be used to target caches modified before or since a particular time period.
# Delete caches modified in the past two hours $ docker build prune --filter since=2h # Delete caches modified more than two hours ago $ docker build prune --filter until=2h
The Docker build cache improves performance by reusing intermediate image layers between builds. This avoids wasted work to recreate layers that already exist and haven’t changed. While the build cache is generally desirable, there are scenarios where you might want to run a build without it. Adding the
--no-cache flag to your builds provides an accurate perspective of what the build would produce when run on a new host.
Stale base images need to be considered alongside the build cache too. Docker reuses local versions of base images by default, which can cause you to build new images on an outdated base. Using the
--pull flag forces Docker to check for updated base images before it starts the build, giving you greater consistency across different environments.