Where Docker disk space actually goes
Images, build cache, stopped containers and volumes each cost you differently to reclaim. What each one is, which are safe to delete, and the one flag that destroys data.
Short answer: run docker system df. It splits what Docker
holds into four rows, and the four are not equally safe to reclaim: images, containers,
local volumes and build cache. Three of them come back by pulling or rebuilding. The
fourth is the only copy of whatever is inside it.
The four rows, safest first
- Build cache. Layers BuildKit kept so your next build starts warm.
Deleting it costs exactly one cold build per project.
docker builder prune -a -fclears it. - Unused images. Base images and old tags nothing references. They come
back from the registry when something pulls them, at the cost of the download.
docker image prune -a -ftakes every image no container uses. - Stopped containers. A stopped container keeps its writable layer.
Anything a process wrote inside the container, and not into a mounted volume, lives in
that layer and goes with it. If that describes data you care about, it was in the wrong
place, and the time to move it is before the prune.
docker container prune -fremoves stopped containers. - Volumes. A named volume is where databases, message queues and anything else with real state keep it. There is no registry behind a volume and no rebuild that brings one back. This row is not a cache and should never be cleared like one.
The flag that turns cleanup into data loss
docker system prune --volumes deletes every volume no container currently
references. "Currently" is the trap: a database whose container is stopped, or removed and
recreated on demand by compose, counts as unreferenced at that moment. People run the flag
to reclaim cache space and delete a local database as a side effect. If you want volume
space back, list them with docker volume ls, look at what each one is, and
remove the ones you can name with docker volume rm, one at a time.
Why the numbers look strange
Two things about Docker's accounting are worth knowing before you compare numbers.
Layers are shared, so deleting three images can free far less than the sum of their listed
sizes. And on Docker Desktop the whole store lives inside a virtual machine disk the host
cannot see into, so the honest measurement is the engine's own system df,
before and after, rather than anything a directory walk on the host can tell you.
Doing it with a tool that keeps score
dev-prune treats container disk as something you look at often and
delete from deliberately. devp caches docker prints the four rows, sized, with
how much the engine says is reclaimable, and deletes nothing. devp caches clear
docker runs the three narrow commands above (build cache, unused images, stopped
containers), prints them before running anything, asks, and measures what came back by
asking the engine again afterwards, so the figure lands in devp stats instead
of being forgotten. Podman, nerdctl, finch and Apple's container engine each get the
same report and their own engine's equivalent of those narrow commands.
Volumes are excluded from that estimate and from those commands: none of the engine
commands dev-prune runs contains the word "volume", and a test fails the build if one
appears. The one path that touches them, devp caches clear docker
--include-volumes, lists the unused volumes by name and takes each deletion as a
typed pick at a real terminal, one unforced docker volume rm per pick. It
refuses --yes, --json and piped input, so no script, scheduler
or AI agent can reach the picking. And typed cold, it does not delete at all: the pick
list arms only within ten minutes of a completed dry run for that engine, so the real
command runs the dry run instead and says so. Nothing bulk, nothing silent.
Common questions
Is docker system prune safe to run?
Without --volumes, mostly: it removes stopped containers, unused networks, dangling images and dangling build cache, all of which come back by pulling or rebuilding. The caveat is stopped containers, whose writable layers go with them, so anything a process wrote inside a container rather than into a volume is lost. With --volumes it stops being a cleanup command: it deletes every volume no container currently references, which includes the database whose container happens to be stopped.
What is using all my Docker disk space?
Run docker system df for the split across images, containers, volumes and build cache, or devp caches docker for the same figures with per-row reclaimable amounts. On build machines the build cache is usually the biggest recoverable row; on machines running databases in containers, volumes often dominate and should be left alone.
How do I delete Docker volumes safely?
By name, one at a time, after looking: docker volume ls, then docker volume rm for the ones you can identify. Avoid docker volume prune and docker system prune --volumes, which delete by reference counting rather than by your judgment. devp caches clear docker --include-volumes wraps the same per-name deletion in a typed pick list that scripts and agents cannot answer.