# How to Clear the Docker Build Cache (and When Not To)

> Delete the Docker build cache with builder prune and buildx prune, see how much space it is using, and understand why --no-cache does not clear anything.

Source: https://latchkey.dev/learn/optimize-ci/clear-docker-build-cache  
Updated: 2026-08-31

The build cache is not stored in your images, so deleting images does not touch it. It has its own command, and on a busy machine it is usually the largest single thing Docker is holding.

BuildKit keeps the result of every build step so a rebuild can skip work that has not changed. That cache lives separately from images and containers, which is why `docker image prune` can free nothing while `docker system df` still reports tens of gigabytes in use.

There are two commands depending on which builder you used, and one common mistake that clears nothing at all.

## See what it is actually using first

```
docker system df

TYPE            TOTAL   ACTIVE   SIZE      RECLAIMABLE
Images          42      3        12.4GB    9.8GB (79%)
Containers      5       1        1.2GB     980MB (81%)
Local Volumes   8       2        3.1GB     2.4GB (77%)
Build Cache     214     0        31.7GB    31.7GB
```

> The Build Cache row is the one this page is about, and it is reclaimable in full: nothing depends on it, it only saves time on the next build.

## Clear it

```
# The build cache, and nothing else
docker builder prune            # dangling cache only, prompts first
docker builder prune -a -f      # everything, no prompt

# If you build with buildx (the default for docker build since v23)
docker buildx prune -a -f

# Only what has not been touched in a week
docker builder prune --filter until=168h
```

> Without `-a` these remove only unused, dangling cache entries. On a machine that builds one project repeatedly that is often a small fraction of the total, which is why the first run so often disappoints.

## The mistake: --no-cache does not clear the cache

`docker build --no-cache` tells one build to ignore what is already cached. It does not delete anything, and the build it runs then writes a fresh set of cache entries on top of the old ones, so disk usage goes up rather than down. If the goal is free space, prune. If the goal is a clean rebuild because you suspect a stale layer, `--no-cache` is right and the space question is separate.

## Which command for which problem

| You want to | Command | Also removes |
| --- | --- | --- |
| Free build cache only | `docker builder prune -a` | Nothing else |
| Free everything unused | `docker system prune -a --volumes` | Stopped containers, unused images, unused volumes and networks |
| Rebuild ignoring cache | `docker build --no-cache` | Nothing, and adds more cache |
| Cap the cache instead of clearing it | `docker buildx prune --max-used-space 20GB` | Nothing else |

> `docker system prune` without `-a` already removes dangling build cache, which is why people report it freeing space they did not expect. It is a blunter instrument than `builder prune` and worth knowing before you run it on a machine with images you want to keep.

## In CI this is a different problem entirely

On an ephemeral runner there is no cache to clear, because the machine is new. The problem there is the opposite one: every build starts cold and pays full price for layers that have not changed. The fix is an external cache backend rather than a prune command, and it is worth setting up before you optimise anything else about a container build.

> On a self-hosted runner that is reused between jobs, the build cache does accumulate and will eventually fill the disk. A scheduled `docker builder prune --filter until=168h` is the usual answer, rather than pruning after every job and losing the benefit.

## Measure before you optimise

Pipeline optimisation usually targets the step people assume is slow. Get the real per-step timings first, because the answer is frequently dependency install or a cold cache rather than the build itself.

```Terminal
# per-job timings for the last 20 runs
gh run list --limit 20 --json databaseId,conclusion,createdAt,updatedAt \
  --jq '.[] | "\(.conclusion)\t\(.createdAt)\t\(.updatedAt)"'

# per-step timing inside one run
gh run view <run-id> --log | grep -E "^\S+\s+.*Run |##\[group\]" | head -40
```

> Compare a cold-cache run against a warm one. If most of the difference is install time, caching is the win; if it is not, caching will change nothing and the build itself needs the attention.

## FAQ

### How do I delete the Docker build cache?

Run `docker builder prune -a -f`, or `docker buildx prune -a -f` if you build through buildx. Without `-a` only dangling entries are removed, which on a machine that builds the same project repeatedly is often a small share of the total.

### Why is my disk still full after docker image prune?

Because the build cache is stored separately from images and `image prune` does not touch it. Run `docker system df` and look at the Build Cache row; on a development machine it is frequently larger than every image combined.

### Does docker build --no-cache clear the cache?

No. It makes one build ignore the existing cache, then writes new cache entries of its own, so disk usage increases. To free space you need a prune command.

### Is it safe to clear the build cache?

Yes. Nothing depends on it, and no image or container is affected. The only cost is that your next build has to redo the steps it would otherwise have skipped.

### How do I stop the build cache growing without pruning it constantly?

Give it a ceiling: `docker buildx prune --max-used-space 20GB`, or configure the limit on the builder itself. That keeps the recent, useful entries and discards the rest automatically.

---

Latchkey runs CI/CD that repairs its own failures. Agent entry points: https://latchkey.dev/agent.txt, https://latchkey.dev/openapi.json, https://latchkey.dev/llms.txt
