Skip to content
LatchkeyLatchkey home

How to Clean Up Docker: Images, Containers, and Volumes

Docker never reclaims anything on its own. Every image you pulled, every container you stopped and every volume you forgot is still on the disk, and one command removes almost all of it.

Docker keeps things because it cannot know what you still want. Stopped containers are kept so you can read their logs, images are kept so a rerun does not re-pull them, and anonymous volumes outlive the container that created them.

The result is a disk that fills gradually and then all at once. Here is what is taking the space, and the smallest command that gets it back.

Find out what is using the space

docker system df        # summary by type
docker system df -v     # every image, container and volume, individually

The one command most people want

# Everything not currently in use, including images no container references
docker system prune -a --volumes

Or clean one thing at a time

CommandRemovesKeeps
docker container pruneAll stopped containersRunning containers and their images
docker image pruneDangling images only, the untagged leftovers of rebuildsEvery tagged image
docker image prune -aEvery image no container referencesOnly images in use right now
docker volume pruneVolumes no container referencesVolumes attached to any container, running or not
docker network pruneNetworks with no containers attachedDefault networks

Filters, for when prune -a is too much

# Only images older than a week
docker image prune -a --filter "until=168h"

# Keep anything you have labelled
docker image prune -a --filter "label!=keep=true"

# One specific image
docker rmi ghcr.io/acme/app:old-tag

What this does not cover

  • The build cache. It is not an image and prune commands aimed at images will not free it. See clearing the Docker build cache.
  • Space inside a running container. That belongs to the container and is only freed when the container is removed.
  • On Docker Desktop, the virtual disk does not always shrink after a prune even though the space is free inside it. That is a separate problem with a separate fix.

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

Frequently asked questions

How do I clean up Docker and free disk space?
Run docker system df to see where the space has gone, then docker system prune -a --volumes to remove everything not currently in use. If that is too aggressive, prune images, containers and volumes separately, or add --filter "until=168h" so only older items are removed.
What is the difference between docker image prune and docker image prune -a?
The plain form removes only dangling images, the untagged leftovers left behind when you rebuild a tag. The -a form removes every image that no container references, including tagged images you may still want. The first is safe and usually frees little; the second frees a lot and can cost you a re-pull.
Does docker system prune delete my data?
Not by default. It leaves volumes alone unless you pass --volumes, and it never touches running containers. With --volumes it does remove unused volumes, which is where a development database usually lives, so check docker volume ls before adding that flag.
How do I remove all Docker images at once?
docker rmi -f $(docker images -aq) removes every image, forcefully. docker image prune -a is the better command in almost every case, because it stops short of images something is actually using.
Can I automate Docker cleanup?
Yes, and a scheduled docker system prune -af --filter "until=168h" is the common form: it reclaims anything untouched for a week and leaves recent work alone. On CI runners that are reused between jobs this is worth setting up before disk-full errors start failing builds.

Related guides

References

Run this faster and cheaper on Latchkey managed runners - self-healing included. Start free → 30-day trial · No credit card