Skip to content
C Codeloom
Docker

Docker Image Cleanup and Prune: Reclaim Disk Without Tears

Disk full from Docker? Learn what fills up, which prune commands are safe, and how to automate cleanup so /var/lib/docker stops eating your machine.

·5 min read · By Codeloom
Beginner 8 min read

What you'll learn

  • What actually consumes disk in Docker
  • The difference between dangling and unused
  • Which prune flags are safe and which are not
  • How to automate cleanup on CI hosts
  • How to keep the build cache from exploding

Prerequisites

  • Basic Docker CLI usage

Every Docker user eventually meets the message “no space left on device” at the worst possible moment. The culprit is almost always accumulated images, stopped containers, dangling volumes, and a build cache that nobody told to stop growing. This article walks through what fills the disk and how to clean it safely.

What and Why

Docker stores everything under /var/lib/docker. That directory holds image layers, container writable layers, volumes, networks, and a build cache. Nothing in there gets deleted automatically. Pull a new tag and the old one sticks around. Rebuild an image and the previous layers linger as dangling. Run a one-off container and its writable layer survives until you remove it.

On a busy CI host this can grow by gigabytes a day. The cleanup commands are easy, but the safe ones and the destructive ones look almost identical, so people often avoid the topic until disk fills.

Mental Model

Docker classifies objects into four buckets, and each has its own prune:

  • Images: dangling (no tag, no children) vs unused (tagged but no container references them).
  • Containers: running vs stopped. Stopped ones still hold their writable layer.
  • Volumes: in-use vs unreferenced. Unreferenced named volumes never disappear on their own.
  • Build cache: kept by BuildKit to speed future builds. Grows without bound by default.

Start small with docker system df to see what is using space. Then prune the right bucket.

Hands-on Example

docker system df
docker system df -v   # detailed view
docker container prune
-> stopped containers only

docker image prune
-> dangling images (untagged, no children)
docker image prune -a
-> ALL images not used by any container (aggressive)

docker volume prune
-> volumes not mounted by any container

docker builder prune
-> build cache entries

docker system prune
-> containers + networks + dangling images + build cache
docker system prune -a --volumes
-> the nuclear option
What each prune command removes

Run docker image prune daily and you reclaim space from rebuilds without touching anything you might still need. Run docker system prune -a --volumes and you may delete the cached base images you were about to use, plus any unmounted volume holding real data.

Common Pitfalls

Running docker system prune -a --volumes on a developer laptop and losing the Postgres volume that backed your local dev database. Named volumes are removed if no container is currently using them, even if a stopped container declared them. There is no undo.

Pruning images by age but forgetting that re-pulling at every CI run will pull layers over the network again. There is a real tradeoff between disk and bandwidth. Tune --filter "until=72h" to match your build cadence.

Cleaning containers but leaving the build cache. With BuildKit, the cache can be the largest single consumer. docker buildx du shows its size. docker buildx prune --keep-storage 10GB caps it.

Believing docker rmi actually frees the space. If another tag or container references those layers, the layers stay. Watch docker system df before and after to confirm.

Aggressively cleaning on production. If your container restarts and the image was pruned, the next pull may be slow or even fail if the registry is down. Prune is for hosts that can re-pull cheaply.

Practical Tips

For a developer machine, a weekly habit is enough. Schedule:

docker container prune -f
docker image prune -f
docker builder prune -f --keep-storage 20GB

For CI runners, add a systemd timer that runs the same commands nightly and sends the output to your monitoring system. Combine with a disk-usage alert at 80 percent.

Cap the BuildKit cache explicitly. Without a cap it will fill the disk one build at a time. The --keep-storage flag is your friend.

Use multi-stage builds and label intermediate images so you can prune just those. Tag base images with semantic versions, not latest, so prune does not accidentally orphan the one you depend on.

If you run Docker Desktop on macOS or Windows, remember it lives inside a VM with its own disk image. Pruning inside Docker frees space inside the VM, but the host VM file does not always shrink. Use Docker Desktop’s “Disk image size” setting and the “Clean / Purge data” option for the final cleanup.

Wrap-up

The prune commands are simple, but using them safely means knowing what each one removes and matching that to where the host lives. A developer laptop deserves gentle, frequent cleanup. A CI host can take an aggressive scheduled prune. Production should rarely prune. Learn the buckets, watch docker system df, and full disks stop being a surprise.