Every container you run, every image you pull, every build you run, it all piles up quietly in the background. Left unchecked, it's not unusual to find Docker eating 20 to 30GB of disk space after a few weeks of active development. Therefore, it becomes important to clean it up safely.
Before deleting anything, check what you actually have:
# Show running containers
docker ps
# Show ALL containers, including stopped ones
docker ps -a
# Count how many stopped containers are sitting around
docker ps -aq -f status=exited | wc -l
# Disk usage breakdown across all Docker objects
docker system dfdocker system df output:
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 14 5 4.2GB 2.8GB (66%)
Containers 23 3 156MB 156MB (100%)
Local Volumes 8 4 2.1GB 600MB (28%)
Build Cache 31 0 1.4GB 1.4GB (100%)
The RECLAIMABLE column is your target, it shows exactly how much space you can get back without affecting anything currently in use.
# Remove a stopped container
docker rm my-container
# Remove multiple at once
docker rm web db cache
# Force remove a running container (in background, it stops first, then deletes)
docker rm -f my-container
# Remove a container and its anonymous volumes
docker rm -v my-containerYou can't remove a running container without -f. Either stop it first with docker stop, or force-remove it with docker rm -f.
# Remove all stopped containers (It prompts for confirmation)
docker container prune
# Skip the confirmation
docker container prune -f
# Only remove containers stopped more than 24 hours ago
docker container prune --filter "until=24h"--rmThe most effective way to avoid container buildup is to never let them accumulate in the first place. Add --rm to any container you don't need to keep. Use --rm for one-off commands, CI tasks, data migrations, quick tests or anything you won't need to revisit. It's the single best cleanup habit you can build.
# Container is automatically deleted the moment it exits
docker run --rm alpine echo "done"
docker run --rm -it ubuntu bashOld and unused images are usually the biggest disk consumers:
# Remove a specific image
docker rmi nginx:1.24
# Remove multiple images
docker rmi nginx:1.24 node:18
# Force remove (even if a stopped container references it)
docker rmi -f old-image:v1
# Remove dangling images (untagged layers left over from builds)
docker image prune
# Remove ALL images not used by any container
docker image prune -a
# Skip confirmation
docker image prune -a -fDangling images are the untagged <none> images you see in docker images, they're leftover intermediate layers from previous builds. Safe to delete.
# Remove a specific volume
docker volume rm mydata
# Remove all volumes not attached to any container
docker volume prune
# Skip confirmation
docker volume prune -f
docker volume prunepermanently deletes data. Always rundocker volume lsfirst to make sure you're not about to wipe something important. There's no undo.
# Remove a specific network
docker network rm my-network
# Remove all unused networks
docker network pruneUnused networks are safe to prune as they hold no data, just configuration.
Build cache is almost always the biggest and safest thing to delete:
# Remove all build cache
docker builder prune
# Remove cache older than 48 hours
docker builder prune --filter "until=48h"
# Skip confirmation
docker builder prune -fBuild cache is 100% safe to delete. The only consequence is that your next build starts from scratch and takes longer, but subsequent builds will cache again normally.
docker system pruneWhen you want to clean everything at once:
# Remove stopped containers, dangling images, unused networks, build cache
docker system prune
# Also remove unused volumes
docker system prune --volumes
# Also remove ALL unused images (not just dangling ones)
docker system prune -a
# Full cleanup, no prompts
docker system prune -a --volumes -f| Flag | What It Also Removes |
|---|---|
| (none) | Stopped containers, dangling images, unused networks, build cache |
-a | All unused images (not just dangling) |
--volumes | Unused volumes |
-f | Skips the confirmation prompt |
Don't run
docker system prune -a --volumesunless you're sure. It removes every container, image, and volume not currently in use, including volumes with data you might still need.
Daily during active development:
docker container prune -f # Stopped containers gone
docker builder prune -f # Build cache clearedWeekly:
docker image prune -a -f # Unused images removed
docker volume prune -f # Orphaned volumes cleared| Command | What It Does |
|---|---|
docker system df | Show disk usage breakdown |
docker rm -f <c> | Force remove a container |
docker container prune | Remove all stopped containers |
docker run --rm | Auto-delete container on exit |
docker image prune -a | Remove all unused images |
docker volume prune | Remove unused volumes |
docker builder prune | Clear build cache |
docker system prune -a --volumes | Full cleanup (use carefully) |
docker system df is always your first move as it shows exactly how much space each type of Docker object is using and how much is reclaimable--rm on docker run for any container you won't need again.docker builder prunedocker volume prune is destructive, data in orphaned volumes is gone permanently; always check docker volume ls firstdocker system prune -a --volumes is the option used only when you're certain nothing currently unused is worth keepingdocker rm removes specific containers you name. docker container prune removes all stopped containers in one go. Use docker rm when you want to be selective; use prune when you want to bulk-clean everything that's no longer running.
docker image prune (without -a) only removes dangling images, untagged layers leftover from builds. It won't touch images that have a tag. Adding -a removes all images not currently used by any container (running or stopped), so if you have images you want to keep but aren't using right now, skip the -a flag.
Yes, always. Build cache just speeds up future builds. Deleting it means your next build takes longer (a cold build), but it won't break anything. Subsequent builds will recreate the cache layer by layer.
--rm tells Docker to automatically delete the container as soon as it exits. Use it for anything you run once and don't need to revisit like one-off commands, scripts, tests, migrations. It's the best way to prevent stopped containers from piling up.
Unfortunately, docker volume prune permanently deletes volume data and there's no built-in recovery. This is why checking docker volume ls before pruning is so important. Going forward, set up regular volume backups.
Learn how to write a Dockerfile: FROM, COPY, RUN and CMD, layer caching, .dockerignore, multi-stage builds, HEALTHCHECK and the mistakes that bloat images.
Choose the right Dockerfile FROM base image: alpine vs slim vs full, pinning tags and digests, multi-stage FROM, platform targeting and the scratch image.
Learn when to use COPY vs ADD in a Dockerfile. Covers build context, --chown and --chmod, COPY --from, the dependency-manifest pattern and .dockerignore.