Prune Docker Safely Without Deleting Production Data
17 Nov 2025docker system prune -a --volumes is one command away from deleting a database volume you needed. It’s also, run carelessly, the most common way people learn what that volume contained the hard way. Pruning is safe — if you know which command touches which thing.
What each prune command actually deletes
| Command | Deletes | Risk |
|---|---|---|
docker container prune |
Stopped containers | Low — they’re already stopped |
docker image prune |
Dangling (untagged) images only | Low |
docker image prune -a |
All images not used by a running container | Medium — includes tagged images you might redeploy from |
docker network prune |
Unused custom networks | Low |
docker volume prune |
Volumes not referenced by any container | High — this is where data loss happens |
docker builder prune |
Build cache | Low, just slows the next build |
docker system prune |
Containers, images, networks (not volumes) | Medium |
docker system prune -a --volumes |
All of the above, including volumes | Highest |
The volume flag is the dangerous one, and it’s opt-in for a reason — docker system prune alone does not touch volumes. If you or a script adds --volumes, you’re saying “also delete anything not currently attached to a running container,” and that “not currently attached” condition is exactly the state a database volume is in for a few seconds during a routine docker compose restart.
1. Check what’s actually on the chopping block first
Never run a prune command blind on a server with real data. Dry-run equivalent — list what would be affected:
docker volume ls -f dangling=true
docker image ls -f dangling=true
For volumes specifically, cross-reference names against what your Compose files expect. A volume named myapp_pgdata disappearing from that list because it briefly wasn’t attached is a completely different situation from a volume named myapp_build_cache_tmp disappearing.
2. Prune specific categories, not everything at once
docker container prune -f
docker image prune -f
docker builder prune -f
This reclaims the vast majority of wasted space — old images, stopped containers, stale build cache — without ever touching volumes. Run this combination regularly (a weekly cron job is reasonable) with no real risk.
3. Handle volumes separately, deliberately
docker volume ls
Go through the list and identify which volumes are genuinely orphaned (from a service you removed entirely, or renamed) versus ones that are just temporarily detached because their container is mid-restart. Remove individually by name once you’re sure:
docker volume rm old-service-data
Never docker volume prune on a host running any stateful service — Postgres, Redis with persistence, uploaded file storage — without first confirming every volume you care about shows as in use by a currently running container. A container that’s stopped for a deploy, even briefly, makes its volume look “unused” to Docker in that instant.
4. Filter pruning by age instead of an all-or-nothing sweep
For images and containers, you can scope the prune to things older than a threshold, which is a safer default for automation than an unscoped sweep:
docker image prune -a --filter "until=168h"
This only removes images untouched for a week, giving you a buffer where anything from a recent deploy is protected even if it’s momentarily unused.
5. Automate the safe part only
If you want a cron job to keep disk usage down, scope it to what’s actually safe:
0 3 * * 0 docker container prune -f && docker image prune -af --filter "until=168h" && docker builder prune -f
Note what’s deliberately absent: no volume prune, no system prune -a --volumes. Volume cleanup stays a manual, deliberate action — it’s the one category where automation risk outweighs the disk space it saves.
The takeaway
docker system prune -a --volumes is fine to know about, not fine to run reflexively. Split your pruning into the safe automated part (containers, images by age, build cache) and the manual, deliberate part (volumes, checked by name against what you actually expect to see). If a script or a tutorial hands you the combined -a --volumes flag on a server with a database, read it twice before you run it.