Docker Prune: From Beginner to Expert
Why Do You Need Docker Prune?
While Docker is incredibly useful, it comes with hidden costs: over time, images, containers, volumes, and networks pile up and quietly consume large amounts of disk space. This isn’t a design flaw in Docker, but rather the result of its core design philosophy. Docker is naturally “conservative” when managing resources—it won’t delete anything on its own, leaving the cleanup work to you. If you don’t actively clean up, your server’s hard drive will quickly fill up.
Five Things That Take Up the Most Space
Understanding what consumes the most space is the first step to effective cleanup. Here are the five main sources of “garbage”:
-
Stopped Containers:
Every time you run a container (even just a one-time command), Docker creates a container instance. These containers don’t automatically disappear after stopping—they still keep their filesystem layers and take up space. -
Dangling Images:
This is the most common source of wasted space. When you rebuild an existing image (for example,docker build -t my-app .
), the old version isn’t deleted. Instead, it loses its tag and becomes a “dangling” or “orphaned” image, showing up as<none>:<none>
in listings. These images are no longer used by any container and are purely historical leftovers. -
Unused Images:
This covers a broader range than dangling images. An image might have a proper tag (likeubuntu:20.04
), but if no containers (running or stopped) are using it, it’s an unused image. You might have downloaded many base images or test images and forgotten to delete them after use. -
Unused Volumes:
Volumes are used for persistent data storage. But if you create a container that uses a volume and later delete the container, that volume won’t be automatically removed. Anonymous volumes (unnamed volumes) are especially easy to forget, growing like digital weeds. -
Unused Networks:
Similar to volumes, when you create custom networks for specific applications but later delete all containers using those networks, the networks themselves don’t disappear. While individual networks don’t take up much space, they accumulate over time.
Regular cleanup of these unused resources not only frees up significant disk space but also makes Docker management more convenient, avoiding the hassle of searching through clutter like “rummaging through boxes to find something.”
The docker prune
Command
To solve these problems, Docker provides a powerful set of prune
commands. These commands are like a Swiss Army knife—each tool has a specific purpose.
docker system prune
This is the most powerful “spring cleaning” tool and the most commonly used. It removes all the following unused resources in one go:
- All stopped containers
- All dangling images
- All unused networks
- All build cache
By default, docker system prune
does not remove unused volumes—this is a very important safety feature to prevent you from accidentally deleting important data.
# Perform a comprehensive system cleanup
docker system prune
# Add -a or --all parameter for more aggressive cleanup, removing all unused images (not just dangling ones)
docker system prune -a
# Add --volumes parameter to also remove unused volumes
docker system prune --volumes
Warning:
docker system prune --volumes
is a dangerous operation. It will delete all volumes not referenced by any container, including named volumes that might contain important data you want to keep. Think twice before using this.
Cleaning Specific Resources
If you don’t want to use the “spring cleaning” command and only want to clean specific types of resources, you can use these more targeted commands. The benefit is clear focus and reduced risk of accidental deletion.
docker container prune
Only removes all stopped containers.
docker container prune
docker image prune
By default, only removes dangling images (<none>:<none>
).
# Only remove dangling images
docker image prune
# Use -a or --all parameter to remove all images not used by any container (including tagged ones)
docker image prune -a
docker volume prune
Only removes unused volumes.
docker volume prune
Warning Again: This command is very dangerous—once deleted, data is gone forever. Docker’s design philosophy is “data first,” so it won’t touch your volumes by default. Before running this command, make sure you really know what you’re doing and have backed up important data.
docker network prune
Only removes all unused networks.
docker network prune
The Safe Order for Cleanup
Docker resources have dependencies: containers depend on images, and volumes and networks are used by containers. Therefore, a safe cleanup order should be:
- Stop and remove containers (
docker stop
/docker rm
ordocker container prune
). - Remove unneeded images (
docker image prune
). - Remove unneeded volumes (
docker volume prune
). - Remove unneeded networks (
docker network prune
).
docker system prune
basically helps you execute this sequence automatically.
Mastering Cleanup Commands: --all
and --filter
for Precise Operations
Just knowing the basic commands isn’t enough. To become a Docker cleanup expert, you must master the parameters that give you precise control.
The Power and Risk of “One-Click Cleanup” Parameters
--all
(-a
) and --volumes
are the most powerful and most easily misunderstood parameters in docker prune
commands.
-
--all
(-a
):
When used withdocker image prune
, this parameter expands the cleanup scope from “dangling images” to “all unused images.” This means even if an image has a name (likenginx:latest
), as long as no container is using it, it will be deleted. This is very useful for cleaning up images you downloaded for testing but never used again. -
--volumes
:
This parameter is exclusive todocker system prune
. It acts like a switch—once turned on,system prune
will also remove unused volumes during cleanup. Again, this can lead to data loss. -
--force
(-f
):
This parameter skips the “Are you sure?” confirmation step and executes deletion directly. It’s useful in automation scripts, but be extra careful when using it manually since you won’t get a chance to reconsider.
Using --filter
: The Surgical Tool
The --filter
parameter transforms docker prune
commands from a “sledgehammer” into a “scalpel.” You can use it to set very specific rules, only deleting resources that meet certain conditions.
The most commonly used filters are until
and label
.
Filtering by Time (until
)
You can delete resources created before a certain time point. The until
value can be a timestamp or a time period (like 24h
).
# Remove all containers stopped for more than 24 hours
docker container prune --filter "until=24h"
# Remove all images unused for more than 10 days
docker image prune -a --filter "until=240h"
# Remove all build cache unused for more than 7 days
docker builder prune --filter "until=168h"
Filtering by Label (label
)
This is the most powerful protection mechanism. You can add a special “protection” label to resources you don’t want accidentally deleted, then tell Docker “don’t touch anything with this label” during cleanup.
This “exclusion” approach is a huge shift. It changes you from “delete what you see” mode to “only delete what’s not labeled” mode, greatly improving safety.
# 1. Create a volume with a protection label
docker volume create --label keep=true important_data
# 2. Delete all unused volumes without the "keep=true" label
# Note the "label!=key=value" syntax
docker volume prune --filter "label!=keep=true"
# 3. Protecting images works the same way
docker tag my-image my-image:latest
# Note: Docker doesn't have a direct command to label images; this is usually done during build with LABEL instruction
docker image prune -a --filter "label!=keep=true"
Once you master filters, you can confidently use docker prune -f
in automation scripts because you know it will only delete what you explicitly allow to be deleted.
Docker Prune Usage Guide
Knowing how to use commands is one thing; knowing when to use them and how to use them safely is another.
Safety Checklist Before Cleanup
Before executing any prune
command, especially with --force
, please go through this checklist:
-
Get a general overview:
docker ps -a
: See what containers you have and their status.docker images -a
: See what images you have and which are dangling.docker volume ls
: See what volumes you have, especially anonymous volumes with strange names.docker network ls
: See what networks you have.
-
Manual inspection:
For resources you’re unsure about, like a volume that looks like it contains important data, usedocker volume inspect <volume_name>
to check its details. -
Rehearse before executing:
Run the command without--force
to see what Docker says it will delete. After confirming it’s correct, use--force
if needed. -
Backup! Backup! Backup!
For production environments or any volumes containing important data, always backup before deletion. Once deleted, it’s really gone forever.
Docker Prune Considerations
In development environments, you can boldly use docker system prune -a --volumes
to free up space. But in production environments, this is like playing with fire. The core principle in production is “stability above all.”
Warning: Don’t randomly run
docker system prune
on production servers, especially when you don’t fully understand what applications and data are running on the server.
Production environment cleanup strategy should be:
- Better to delete one by one than everything at once: Use more precise commands like
container prune
,image prune
with--filter
. - Be extra careful with automation: If you must automate cleanup in production, always use filters with “protection” labels to ensure core applications and data are never accidentally deleted.
- Understand applications, don’t just rely on tools:
docker prune
is a single-minded tool—it only looks at whether resources “are referenced” without caring about their business importance. Before cleanup, you must understand the role of each volume and image from an application perspective.
Using Docker Prune for Automated Cleanup in CI/CD Pipelines
CI/CD environments are disaster zones for Docker garbage generation. Every build and test produces large amounts of temporary images and containers. Without control, CI/CD server disks will quickly explode.
Why Does CI/CD Need Cleanup?
A typical CI/CD process might include:
- Pull the latest code.
- Build a new image using
Dockerfile
. - Start a container with this new image to run tests.
- After tests pass, push the image to a repository.
This process leaves behind at least one dangling image (old version) and one stopped container. Over time, the numbers become staggering. Therefore, adding cleanup steps at the end of CI/CD pipelines is crucial.
Cleanup Example in GitLab CI/CD
In GitLab CI/CD, you can add cleanup commands in the after_script
section of your .gitlab-ci.yml
file. Commands in after_script
run whether the pipeline succeeds or fails, making them perfect for cleanup work.
stages:
- build
- test
- cleanup
build_job:
stage: build
script:
- docker build -t my-app:$CI_COMMIT_SHA .
- docker push my-app:$CI_COMMIT_SHA
test_job:
stage: test
script:
- docker run my-app:$CI_COMMIT_SHA npm test
cleanup_job:
stage: cleanup
script:
# Only clean resources older than 1 hour, giving parallel tasks enough time
- docker system prune -a -f --filter "until=1h"
# For safer approach, you can just clean dangling images and stopped containers
# - docker image prune -f
# - docker container prune -f
# Ensure this task always runs
when: always
Note: Using the
until
filter is a good practice to avoid cleaning resources that might still be used by other parallel tasks.
Build Cache Trade-offs: Speed vs. Cleanliness?
docker system prune
clears build cache, meaning the next build will start from scratch and be slower. This is a typical trade-off between “performance” and “cleanliness.”
- For performance: Keep build cache for faster builds. But disk usage will continue growing.
- For cleanliness: Clean build cache every time (
docker builder prune
). Low disk usage, but every build is slow like the first time.
The best compromise is periodic cleanup rather than cleaning every time. For example, you can set up a weekly scheduled task specifically for cleaning old build cache.
# Only delete build cache unused for more than a week
docker builder prune --filter "until=168h"
Docker Prune vs. Other Commands
docker-compose down
vs. docker system prune
docker-compose
users often struggle with: Should I use docker-compose down
or docker system prune
? They’re very different.
Feature | docker-compose down |
docker system prune |
---|---|---|
Scope | Project scope: Only manages resources defined and created by the current docker-compose.yml file. |
System scope: Manages all Docker resources on the host, regardless of how they were created. |
Default behavior | - Remove containers - Remove networks |
- Remove stopped containers - Remove dangling images - Remove unused networks |
Volume handling | Doesn’t remove volumes by default. Need -v or --volumes parameter. |
Doesn’t remove volumes by default. Need --volumes parameter. |
Image handling | Doesn’t remove images by default. Need --rmi all (remove all) or --rmi local (only remove untagged) parameter. |
Only removes dangling images by default. Add -a to remove all unused. |
A typical disaster scenario:
You have an important application (like a database) started with docker-compose
that uses a named volume my_db_data
. Later, to clean up disk space, you run docker system prune --volumes
in another project directory or root directory. Since the docker-compose
containers might be stopped at that time, the prune
command will consider my_db_data
an “unused” volume and ruthlessly delete it.
Think of it this way:
docker-compose down
is for dismantling a specific application.docker system prune
is for doing spring cleaning on the entire system.
They serve completely different purposes and should never be mixed up.
Common Problems with Docker Prune
Why Wasn’t Disk Space Freed?
This is the most common question: “I ran prune
, but df -h
shows no change in disk space!”
Most common reasons:
- Docker daemon still holding file handles: Sometimes, even after resources are deleted, the Docker daemon might not have released file locks. Restarting the Docker daemon usually solves this (
systemctl restart docker
). - The real space-consuming stuff wasn’t deleted:
prune
doesn’t delete volumes and tagged images by default. Maybe you really needdocker system prune -a --volumes
. - “Hidden” occupied space: The real space consumers are in Docker’s
overlay2
directory (usually at/var/lib/docker/overlay2
). Even after deleting containers and images, some underlying storage layers might not be properly cleaned due to various reasons. Restarting Docker or, in extreme cases, cleaning the entire Docker directory (very dangerous!) might be the last resort.
Why Won’t a Resource Delete?
You’re sure a container is stopped and an image isn’t being used, but prune
just won’t delete it.
Possible reasons:
- Something is still using it: You might have missed a container using that resource (even stopped containers occupy images and volumes). Carefully check with
docker ps -a
anddocker volume inspect
. - It’s the base for another image: An image might be a base layer (parent image) for another image. In this case, unless you delete all child images depending on it, it won’t be deleted.
Cleanup Commands Hang or Are Very Slow
When you have thousands of Docker objects, docker system prune
might run very slowly or even hang. This is because it needs to figure out all the relationships between everything and calculate what can be safely deleted—a very I/O-intensive operation.
Solutions:
- Step-by-step cleanup: Don’t use
system prune
; instead, runcontainer prune
,image prune
, etc. separately. - Use filters: The
until
filter can significantly reduce the number of objects to check, thus speeding things up. - Regular cleanup: Don’t wait until you have tens of thousands of objects before thinking about cleanup. Develop a habit of regular cleanup, handling small amounts each time for much faster operation.
Summary
docker prune
is an essential tool, but it’s also a double-edged sword. Docker’s naturally “conservative” design means system maintenance responsibility ultimately falls on the user.
Key Points
- Default is safe: The default behavior of
prune
commands is relatively safe—it won’t touch your data (volumes) or useful images. - Beware dangerous parameters:
--all
and--volumes
greatly increase cleanup intensity but also bring risk of data loss. - Filters are your safety net: Learning to use
label
anduntil
filters lets you enjoy automation convenience while ensuring core resource safety. - Environment determines strategy: Development environments can be aggressive; production environments must be cautious.
- Cleanup is mandatory work, not optional: Ignoring Docker cleanup will eventually lead to disk exhaustion, performance degradation, and management chaos.
The general rule is: When in doubt, don’t delete. Before deleting, check. For important data, always backup.