5 min readdevops

Reclaiming disk space from Docker

Docker quietly fills your disk with dangling layers and unused images. Here is how to see what is eating the space and clean it up safely — by hand or on a cron.

On this page

You deploy, you rebuild, you run one more test. Weeks go by, and then one morning a build fails with no space left on device. You SSH in, run df -h, and there it is: a couple of gigabytes free on a disk that should have plenty. Docker has quietly eaten the rest, and it is not going to give it back on its own.

This happens on every box that runs Docker for a while — a CI runner, a staging VPS, your own laptop. The good news is that the cleanup is almost always safe and takes about a minute once you know which commands to reach for.

# Why Docker fills the disk

Every docker build produces a stack of image layers. When something in your Dockerfile changes — a new dependency, a fresh copy of your source — Docker builds new layers on top and leaves the old ones behind. Those orphaned layers keep their data but lose their tag and name. They show up as <none> in docker images and are called dangling images.

They do nothing useful. They are not referenced by any current image or container. And Docker never removes them automatically — it assumes you might still want them, so the pile just grows.

# See where the space went

Before deleting anything, find out what is actually taking up room. One command gives you the whole picture:

docker system df

It breaks usage down by images, containers, local volumes and the build cache, and — the column that matters most — how much is reclaimable. That number is your upside from cleaning up.

If you want to inspect the images themselves, this format string is easy to read:

docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.ID}}\t{{.Size}}"
Read the reclaimable column first

docker system df tells you whether cleanup is even worth it. If reclaimable is near zero, your problem is somewhere else — application logs, database files, or an overlarge single image — and pruning will not help. Always diagnose before you delete.

# Remove the dangling layers

The safest cleanup targets only the untagged, unreferenced layers:

docker image prune

Docker shows you what it is about to remove and asks for confirmation. Nothing tagged or in use is touched, so this is the low-risk first move. On a busy build machine it often frees a surprising amount on its own.

# Remove every unused image

If you have whole images that are no longer used by any container — even stopped ones — you can go further:

docker image prune -a

The -a flag changes the scope entirely: instead of only dangling layers, it removes every image not currently backing a container. On a staging or CI box that rebuilds constantly, this is usually the command that reclaims real gigabytes.

If you deploy often and want to keep recent images around, filter by age:

docker image prune -a --filter "until=720h"

That keeps anything newer than 30 days (720 hours) and removes the rest.

Keep a rolling window

The until filter is the sweet spot for servers with frequent deploys: old builds get cleaned up automatically, but a recent image is still on disk if you need to roll back in a hurry. Tune the window to match how far back you would ever redeploy.

# The nuclear option

When you want a completely clean slate — images, stopped containers, unused networks, and orphaned volumes — there is one command for all of it:

docker system prune -a --volumes

This is perfect for a dev laptop or a throwaway VPS you rebuild regularly. It is also the command most likely to ruin your day if you run it in the wrong place.

Volumes hold your data

--volumes deletes local volumes that no running container is using — which can include a database volume whose container merely happens to be stopped. On a production host, list what is running and what volumes exist before you type this. When in doubt, prune images and containers separately and leave volumes alone.

# Automate it so you never think about it again

Cleaning up by hand works until you forget for a month. A weekly cron job keeps the disk healthy without any attention:

# crontab -e
0 3 * * 0 docker image prune -a -f >> /var/log/docker-prune.log 2>&1

Every Sunday at 3am it prunes unused images without prompting (-f skips the confirmation) and logs the result so you can see what was reclaimed. Note that this only prunes images — it deliberately leaves containers and volumes alone, which is exactly what you want running unattended.

# Command cheat sheet

CommandWhat it does
docker system dfShow space used and how much is reclaimable
docker image pruneRemove dangling (untagged) layers only
docker image prune -aRemove every image not backing a container
docker image prune -a --filter "until=720h"Same, but keep images newer than 30 days
docker system prune -a --volumesRemove images, stopped containers, networks and unused volumes

Start with docker system df every time. Nine times out of ten a single docker image prune -a recovers several gigabytes without breaking anything — and a small weekly cron makes sure you never hit no space left on device in the middle of a deploy again.

views

Click to show appreciation

Discussion