Prune Docker Volumes Without Guessing What Gets Deleted
You will finish with a controlled way to remove Docker volumes that no container references, while keeping named application data out of the default cleanup. The examples use Docker CLI 29.8.1 from docker-ce-cli package version 5:29.8.1-1~ubuntu.24.04~noble.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about fifteen minutes. You need access to the Docker daemon and a shell. This is a destructive operation: a pruned volume and its contents are not restored by Docker. Take a backup or export anything you may need before continuing. Docker access is often privileged through the docker group; use sudo only if your local setup requires it.
1. Check the command you have installed
Read the local command's help before choosing an option. This is a read-only check:
$ docker volume prune --help
Usage: docker volume prune [OPTIONS]
Remove unused local volumes
Options:
-a, --all Remove all unused volumes, not just anonymous ones
--filter filter Provide filter values (e.g. "label=<label>")
-f, --force Do not prompt for confirmation
Checkpoint: confirm the client and package version as well:
$ docker version --format '{{.Client.Version}}'
29.8.1
$ dpkg-query -W -f='${Package} ${Version}\n' docker-ce-cli
docker-ce-cli 5:29.8.1-1~ubuntu.24.04~noble
The server must also be reachable. If docker version reports a daemon error, fix the Docker context or daemon access first. Do not treat sudo as a repair for a stopped or remote daemon.
2. Understand the default before touching data
Without --all, the command removes unused anonymous volumes only. An unused volume is one that no container references. Named volumes are not included in this default cleanup, which is why an ordinary docker volume prune is narrower than many people expect.
The --all option widens the candidate set to unused anonymous and named volumes. That can include database, uploads and cache volumes created by Compose or another deployment tool. Do not add it merely to make the command remove more data.
List volumes without changing them:
$ docker volume ls
DRIVER VOLUME NAME
local example_cache
local example_database
For a closer look at volumes Docker currently considers dangling, use the read-only listing filter:
$ docker volume ls --quiet --filter dangling=true
example_cache
This is an inspection checkpoint, not a reservation. Containers can be created or removed between the listing and the prune, so re-check active deployments immediately before deletion.
3. Check which containers use important volumes
Inspect a volume you recognise before deciding that it is disposable:
$ docker volume inspect example_database
[
{
"Name": "example_database",
"Mountpoint": "/var/lib/docker/volumes/example_database/_data"
}
]
The exact JSON contains more fields and varies by Docker version. The useful first checks are the name, labels and mountpoint. For a container-level view, show mounts on running containers:
$ docker ps --format 'table {{.Names}}\t{{.Mounts}}'
NAMES MOUNTS
web example_uploads
database example_database
Also check stopped containers before removing a named volume. A stopped container can still reference it, so it does not make the volume a prune candidate, but it may reveal an application that will be restarted later. If a Compose project owns the volume, inspect that project's configuration and backup policy rather than inferring safety from the volume name.
4. Use a label filter when ownership is explicit
The prune command accepts key=value filters. The supported filter is label, including positive and negative forms. For example, this targets only unused volumes carrying a deliberate cleanup label:
$ docker volume prune --all --filter 'label=cleanup=approved'
WARNING! This will remove all unused local volumes with the selected filter.
Are you sure you want to continue? [y/N]
Do not press y unless the candidate set is understood. The label does not protect a volume from deletion; it selects it for deletion when the volume is unused. Create and maintain such labels as part of the deployment process, not after a cleanup has gone wrong.
Use a negative label filter only when its meaning is clear. For example, --filter 'label!=retention=keep' selects volumes without that label, which is an exclusion rule rather than a list of volumes explicitly approved for removal.
Multiple filters with different keys are combined with AND logic. Repeating the same filter key combines its values with OR logic. Keep the command short enough to review; a filter expression is not a substitute for a backup.
5. Run the narrow cleanup interactively
After the checks above, run the default form without --force:
$ docker volume prune
WARNING! This will remove anonymous local volumes not used by at least one container.
Are you sure you want to continue? [y/N] y
Deleted Volumes:
<volume id or name>
Total reclaimed space: <amount>
Docker asks for confirmation. A response other than y leaves the volumes in place. The deleted-volume list and reclaimed-space value depend on the daemon state, so do not script against a fixed line count or amount.
Checkpoint: list dangling volumes again:
$ docker volume ls --quiet --filter dangling=true
Any remaining entries may be named volumes excluded by the default, volumes created during the operation, or volumes that still need a separate review. An empty result is useful, but it is not proof that every application has a current backup.
6. Widen the operation only with an explicit decision
Use --all only when named volumes are part of the intended cleanup and you have checked their contents or retained a recoverable backup:
$ docker volume prune --all --filter 'label=cleanup=approved'
WARNING! This will remove all unused local volumes matching the filter.
Are you sure you want to continue? [y/N]
This can remove persistent data from an unused database or an old deployment. There is no Docker undo command for a successful prune. Recovery means restoring the volume's data from a backup or recreating the application from its deployment source. If you cannot name that recovery path, stop at the confirmation prompt.
Do not use --force for a first run. It suppresses the prompt and is intended for a reviewed, non-interactive procedure. If you later automate a filtered prune, log the exact command, keep the filter in source control, and schedule it only after the backup and retention checks have succeeded.
Common traps
- Adding
--allby habit: this changes the operation from anonymous-only cleanup to deletion of unused named volumes too. - Confusing unused with empty: Docker's candidate rule is about container references, not whether the volume directory contains files.
- Trusting a volume name: names such as
cache,dataor a Compose project prefix are not a backup policy. - Assuming the prompt is a preview: it describes the operation, but it does not provide a reversible transaction. Review the host and labels before invoking prune.
- Running as root unnecessarily: use ordinary Docker access when it works. If a privileged invocation is required, make the privilege boundary visible and review the command as carefully as the deletion.
Done means
- You confirmed the installed Docker CLI and daemon access.
- You checked the default scope and decided whether named volumes are in or out.
- You inspected important volumes, their labels and their container references.
- You have a backup or recovery path for every volume that could contain needed data.
- You ran an interactive, appropriately filtered prune and reviewed its output.
- You verified the remaining dangling-volume list and recorded what was removed.