Docker Prune: How to Safely Clean Up Docker Disk Usage
If you have run Docker for more than a few weeks, you have almost certainly watched your disk quietly fill up. You build an image, tweak the Dockerfile, build again, run a container, stop it, pull a new base image, and repeat. Each of those steps leaves something behind. Eventually `df -h` shows a worrying number, your builds start failing with “no space left on device,” and you go looking for the magic command that frees it all up. That command is `docker prune` — a family of cleanup operations built into Docker that remove the junk Docker accumulates as you work.
This guide explains exactly why Docker eats disk space, what each prune command removes, and — most importantly — how to prune without accidentally deleting data you actually wanted to keep.
Key Takeaways
• Docker accumulates disk usage through stopped containers, dangling and unused images, unused volumes, unused networks, and build cache.
• `docker system prune` is the everyday cleanup: it removes stopped containers, dangling images, unused networks, and build cache.
• The `-a` flag changes the meaning of prune from “remove obvious junk” to “remove every image not used by a running container” — powerful but easy to regret.
• `docker volume prune` deletes DATA. Volumes hold databases and persistent files. Never run it blindly on a production server.
• Always run `docker system df` first to see what is actually using space before you prune anything.
Why Does Docker Use So Much Disk Space?
Docker is efficient at sharing layers, but it is also conservative: it almost never deletes anything automatically. Everything you create stays on disk until you explicitly remove it. Four categories of leftovers are responsible for nearly all “where did my disk go?” moments:
| Leftover | What it is | How it piles up |
|---|---|---|
| Stopped containers | Containers that exited but were never removed | Every `docker run` without `–rm` leaves a stopped container behind |
| Dangling images | Untagged image layers (` |
Every rebuild orphans the previous image’s layers |
| Unused images | Tagged images not used by any container | Old versions and one-off pulls accumulate forever |
| Unused volumes | Volumes not attached to any container | Removing a container does not remove its named/anonymous volumes |
| Build cache | Cached layers from `docker build` / BuildKit | Grows with every build, especially on busy CI hosts |
The single most useful habit before any cleanup is to see what is actually consuming space. Docker has a built-in command for exactly that:
“`bash docker system df “`
This prints a summary table:
“` TYPE TOTAL ACTIVE SIZE RECLAIMABLE Images 42 6 18.3GB 14.1GB (77%) Containers 11 3 210MB 180MB (85%) Local Volumes 9 4 3.2GB 1.1GB (34%) Build Cache 156 0 6.7GB 6.7GB (100%) “`
For a more detailed, per-object breakdown, add the verbose flag:
“`bash docker system df -v “`
The `RECLAIMABLE` column tells you how much you can safely free. If most of your space is in build cache and dangling images, a basic prune solves it. If it is in volumes, slow down — that is where data lives.
What Does `docker system prune` Actually Remove?
`docker system prune` is the command most people mean when they say “prune Docker.” By default it removes:
- All stopped containers
- All dangling images (untagged leftover layers)
- All unused networks
- All build cache
“`bash docker system prune “`
It will ask you to confirm before doing anything:
“` 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] “`
Notice what is not in that list by default: tagged images you are not currently using, and volumes. The default `docker system prune` is deliberately conservative — it clears genuine junk and leaves your data and named images alone. For most developers, running this weekly is the right baseline.
To skip the confirmation prompt (useful in scripts and cron jobs), add the `-f` / `–force` flag:
“`bash docker system prune -f “`
What Does the `-a` Flag Do — and Why Is It Risky?
Here is where people get surprised. Adding `-a` (`–all`) to `docker system prune` widens the net dramatically:
“`bash docker system prune -a “`
With `-a`, Docker removes all unused images, not just dangling ones. “Unused” means any image not referenced by an existing container. The confirmation message changes accordingly:
“` WARNING! This will remove:
- all stopped containers
- all networks not used by at least one container
- all images without at least one container associated to them
- all build cache
“`
The `docker prune` command everyone copy-pastes from a forum — `docker system prune -a` — is also the one most likely to cause an “oh no” moment, because the `-a` flag changes its meaning from “clean up obvious junk” to “remove every image not used by a running container.” On a dev box that is fine. On a server where you have images pulled for occasional jobs, paused stacks, or anything not running right this second, `-a` will happily delete images you will then have to re-pull (slow) or rebuild. And the truly dangerous sibling, `docker volume prune`, removes unused volumes — which is where container DATA (your database!) lives, so a stray `volume prune` can erase data no backup expected to lose. The safe habit: run `docker system df` FIRST to see what is actually using space, prune WITHOUT `-a` to clear genuine junk, and treat anything touching volumes as a “stop and double-check what is attached” operation. Prune reclaims disk; `-a` and `volume prune` reclaim things you might have wanted — know exactly what each removes before you confirm.
The dangling-vs-unused distinction is the crux of it:
- Dangling = an untagged image (`
: `), usually a leftover layer set orphaned by a rebuild. Almost always safe to delete. - Unused (`-a`) = any tagged image that no container currently references. This includes images you pulled deliberately for a job that is not running this second.
On your laptop, `docker system prune -a` is a great reset. On a server, prefer the plain version unless you genuinely want to clear every non-running image.
What Are the Individual Prune Commands?
`docker system prune` is a convenience wrapper. Each object type also has its own targeted prune command, which is safer because you control exactly what is cleared.
“`bash
docker container prune
docker image prune
docker image prune -a
docker network prune
docker builder prune
docker builder prune -a
docker volume prune “`
Here is the full picture of what each command removes:
| Command | Removes | Data risk |
|---|---|---|
| `docker system prune` | Stopped containers, dangling images, unused networks, build cache | Low |
| `docker system prune -a` | Above + all images not used by a running container | Medium — re-pull/rebuild cost |
| `docker container prune` | All stopped containers | Low |
| `docker image prune` | Dangling (untagged) images only | Low |
| `docker image prune -a` | All images not used by a container | Medium |
| `docker network prune` | All unused networks | Low |
| `docker builder prune` | Unused build cache | Low |
| `docker volume prune` | Unused volumes | HIGH — deletes persistent data |
You can target prunes with filters too. For example, only remove build cache older than 7 days:
“`bash docker builder prune –filter “until=168h” “`
Or only remove images created more than 30 days ago:
“`bash docker image prune -a –filter “until=720h” “`
Filters let you keep recent work while clearing genuinely stale objects — a good middle ground on servers.
Why Is `docker volume prune` the One to Fear?
Repeat after me: volumes are where your data lives. When you run a database container — Postgres, MySQL, MongoDB, Redis with persistence — the actual data sits in a Docker volume, not in the container’s writable layer. That is intentional: containers are disposable, volumes persist.
`docker volume prune` removes any volume not currently attached to a container. That sounds safe until you realize a stopped database container, a temporarily scaled-down service, or a volume referenced only in a `docker-compose.yml` that is not running right now can all leave their volumes “unattached.”
“`bash
docker volume prune “`
By default, `docker volume prune` only removes anonymous volumes. To also remove named volumes (where most real data lives), you must opt in explicitly:
“`bash docker volume prune -a “`
That `-a` is the difference between clearing throwaway anonymous volumes and wiping the named volume holding your production database. Before pruning volumes, always list what exists and inspect anything you are unsure about:
“`bash docker volume ls docker volume inspect my_database_data “`
The safe rule: never run `docker volume prune` on a production host as part of routine cleanup. If you must reclaim volume space, identify the specific unused volume by name and remove it deliberately:
“`bash docker volume rm specific_throwaway_volume “`
How Should You Schedule Docker Cleanup?
On busy hosts — CI runners, build servers, shared dev machines — disk fills faster than anyone remembers to clean it. Automating a conservative prune is sensible; automating an aggressive one is asking for an incident.
A safe scheduled cleanup clears build cache and dangling images but never touches volumes or running workloads. Here is a cron entry that runs a conservative prune every night at 3 AM:
“`bash
0 3 * * * /usr/bin/docker system prune -f –filter “until=24h” >> /var/log/docker-prune.log 2>&1 “`
Note what this does and does not do: it uses `-f` to skip the prompt (required in cron), it includes a time filter so very recent objects are spared, and it deliberately omits `-a` and any volume operation. That combination keeps disk in check without ever risking data or forcing slow re-pulls of images you use occasionally.
If you want to reclaim build cache specifically — the most common culprit on CI hosts — target it directly:
“`bash 0 3 * * * /usr/bin/docker builder prune -f –filter “until=72h” >> /var/log/docker-builder-prune.log 2>&1 “`
For more on running containers reliably in production, see our primer and the guide on .
Run Docker the way it is meant to be run, with DarazHost
Aggressive cleanup is only scary when a mistake is unrecoverable. DarazHost VPS and dedicated servers give you full root access and generous SSD/NVMe storage to run Docker properly — plus automatic backups, so even disk cleanup and container management have a safety net. If a `volume prune` ever goes sideways, you have a restore point instead of a permanent loss. It is the controllable, container-friendly environment your workloads need, backed by 24/7 support. Learn more about building scalable container infrastructure in our strategic guide to cloud hosting and containers.
What Is the Safe Pruning Workflow?
Putting it all together, here is the workflow that reclaims disk without surprises:
“`bash
docker system df
docker system df -v
docker system prune -f
docker system df
docker image prune -a
docker volume ls “`
Follow those steps in order and you reclaim the gigabytes Docker hoards while keeping your images, your stacks, and — above all — your data intact.
Frequently Asked Questions
Does `docker prune` delete running containers? No. None of the prune commands touch running containers. `docker container prune` removes only stopped containers, and `docker system prune -a` removes only images not used by an existing (including running) container. Anything actively running is always preserved.
What is the difference between `docker system prune` and `docker system prune -a`? The default removes dangling (untagged) images. Adding `-a` removes all unused images — every tagged image not referenced by a container. The `-a` version frees much more space but may delete images you will need to re-pull or rebuild later.
Will `docker volume prune` delete my database? It can. Volume prune removes volumes not currently attached to a container. If your database container is stopped or scaled down, its volume becomes a deletion candidate. With `-a`, even named volumes are removed. Never run it as routine cleanup on production.
How do I check Docker disk usage before pruning? Run `docker system df` for a summary or `docker system df -v` for a per-object breakdown. The `RECLAIMABLE` column shows how much space you can safely free.
What does the `-f` flag do in prune commands? The `-f` (or `–force`) flag skips the interactive confirmation prompt. It is necessary for scripts and cron jobs, but use it carefully — without the prompt, there is no second chance to read the warning before deletion happens.