Docker is quietly one of the biggest disk hogs on a working machine. Every image pull, every rebuild, every short-lived container, and every layer of build cache leaves something behind. Run it for a few weeks and you can lose tens of gigabytes to images you forgot about and cache you never see.
Cleaning it up is easy. Cleaning it up safely takes a little more care, because two of the flags people copy off the internet — -a and --volumes — can delete things you actually wanted, including a database. The goal here is to reclaim space without that nasty surprise.
This guide starts with measuring what’s actually using space, then works through pruning each resource type in order, and finishes with the two flags that bite people and how to use them deliberately.
First, see what’s actually using space
Don’t prune blind. Before deleting anything, ask Docker where the space went:
docker system df
You get a summary table broken into four categories, with a reclaimable column that tells you how much you could free:
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 24 4 11.2GB 8.6GB (76%)
Containers 9 2 142MB 138MB (97%)
Local Volumes 12 3 4.1GB 2.9GB (70%)
Build Cache 86 0 6.3GB 6.3GB
That alone tells you a lot. In the example above the build cache and unused images are the real weight, and volumes are mostly in use. For a per-item view — which specific image or volume is huge — add -v:
docker system df -v
The four things Docker stores
Cleanup makes more sense once you know what you’re deleting. Docker keeps four kinds of resource on disk, and they carry very different risk:
What Docker stores, and how risky it is to delete
| Images | Pulled or built layers. Unused ones are safe to remove; you re-pull or rebuild if needed. |
|---|---|
| Containers | Running and stopped instances. Stopped ones are usually safe to remove. |
| Volumes | Persistent data — databases, uploads, config. Deleting these loses data. Highest risk. |
| Build cache | Intermediate build layers. Always safe to remove; only costs you a slower next build. |
| Networks | User-defined networks. Unused ones are safe to remove. |
Two of these — build cache and dangling images — are essentially free to delete. Volumes are the opposite. Keep that ranking in mind and most cleanup decisions answer themselves.
Pruning each resource on its own
Targeted prunes are the safe way to work, because each command only touches one category and you can see exactly what’s going.
Build cache is the easiest win and carries no data risk:
docker builder prune
Stopped containers — anything exited and not removed:
docker container prune
Dangling images — untagged leftovers from rebuilds. Safe, and usually a decent chunk of space:
docker image prune
To go further and remove all images not used by a running container, including tagged ones, add -a. This is more aggressive — read the next section before you do it:
docker image prune -a
Unused networks — user-defined networks no container is attached to:
docker network prune
Each of these asks for confirmation and prints what it removed, so you can run them one at a time and watch the space come back with docker system df.
docker system prune: the all-in-one
When you want to sweep several categories at once, docker system prune rolls them together:
docker system prune
Plain, with no flags, this removes:
- all stopped containers
- all networks not used by at least one container
- dangling images
- unused build cache
It does not remove named volumes, and it does not remove tagged images that simply aren’t running. That makes the bare command reasonably safe — it clears genuine leftovers and leaves your data and your tagged images alone.
WARNING! This will remove:
- all stopped containers
- all networks not used by at least one container
- all dangling images
- all dangling build cache
Are you sure you want to continue? [y/N]
Read that prompt every time. Docker tells you exactly what it’s about to delete before you confirm, and the list changes depending on which flags you added.
The two flags that bite: -a and —volumes
This is the part to slow down on. The defaults are safe; the flags are where people lose data.
-a (or --all) widens image removal from dangling only to every image not used by a running container. That includes images you pulled or built and aren’t running right now but will want again. Nothing is lost permanently — you can re-pull or rebuild — but on a slow connection or a big image, that’s a painful wait you didn’t need.
# Removes stopped containers, unused networks, build cache,
# AND every image not used by a running container
docker system prune -a
--volumes is the dangerous one. It tells prune to also remove volumes that aren’t attached to a container. The trap: a stopped database container’s volume looks unused. If that database isn’t running when you prune, its volume can be deleted, and that’s your data gone — no recycle bin, no undo.
# Also deletes volumes not currently attached to a container
docker system prune --volumes
Combine both and you have the maximum-cleanup, maximum-risk command:
docker system prune -a --volumes
Cleaning volumes deliberately
When you genuinely do want to clear volumes, do it as its own step so you can see the list first. Show what exists:
docker volume ls
Prune only volumes that aren’t attached to any container:
docker volume prune
To remove a specific volume you know you don’t need:
docker volume rm <volume-name>
If a volume holds data you might want later, back it up before removing it. A quick tar of a named volume looks like this:
docker run --rm \
-v my-volume:/data \
-v "$(pwd)":/backup \
alpine tar czf /backup/my-volume.tar.gz -C /data .
That spins up a throwaway Alpine container, mounts the volume read-write and your current folder, and writes a compressed archive you can keep. There’s more on how named volumes differ from bind mounts in the Docker volumes guide.
A safe cleanup routine
Reclaiming Docker disk space without losing data
- Run docker system df (add -v) to see where the space actually went
- Start any important containers first, so their images and volumes count as in-use
- Clear the safe stuff: docker builder prune and docker image prune (dangling)
- Remove stopped containers and unused networks with their own prune commands
- Need more? docker system prune (no flags) sweeps leftovers but keeps volumes
- Only add -a once you accept re-pulling tagged images later
- Only add --volumes after confirming no stopped container holds data you want
- Re-check docker system df to confirm the space came back
Wrapping up
Most Docker disk problems come down to forgotten images and build cache, both of which are safe to clear. Start with docker system df so you’re deleting based on facts, not guesses. Reach for the targeted prunes first, then plain docker system prune when you want a broader sweep. Save -a for when you accept re-pulling later, and treat --volumes as the command that can erase a database — because it can.
If a cleanup is part of sorting out a stuck stack, the Docker Compose beginner guide covers the down vs down -v distinction that trips people up for the same reason. For more day-to-day maintenance, browse the Docker & Containers guides.