16.3.2.3 Dangling Volume Bloat
A focused guide to Dangling Volume Bloat, connecting core concepts with practical Docker and container operations.
Dangling volume bloat is the accumulation of volumes, named and anonymous alike, that are no longer attached to any container, and unlike images or containers, Docker provides no built-in size reporting for individual volumes by default, which makes this specific category of disk usage considerably harder to quantify and prioritize for cleanup than the other, more directly visible categories.
The size visibility gap specific to volumes
docker images and docker ps -s both report size directly as part of their normal output, but docker volume ls reports no size information at all, which means identifying which dangling volumes are actually worth cleaning up, versus which are negligibly small and not worth the effort or risk, requires an extra, manual step that the other resource categories do not:
docker volume ls -f dangling=true
DRIVER VOLUME NAME
local pgdata-old
local a1b2c3d4e5f6...
local redis-cache-test
None of this output indicates how much actual disk space any of these volumes occupy, which is the core practical challenge this specific category of bloat presents compared to images or containers.
Calculating actual volume sizes manually
Because Docker does not report this directly, determining actual size requires running a throwaway container that mounts each volume and reports on its content:
for v in $(docker volume ls -f dangling=true -q); do
echo -n "$v: "
docker run --rm -v "$v":/data alpine du -sh /data 2>/dev/null | cut -f1
done
Running this kind of script across every dangling volume on a host produces the size visibility that docker volume ls itself does not provide, which is necessary before making an informed decision about which dangling volumes are actually worth the effort of investigating further before removal, versus which can be safely ignored as negligible.
docker system df's aggregate but imprecise volume reporting
docker system df does report an aggregate size for local volumes as a category, which provides a useful overall sense of scale even without per-volume detail:
docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Local Volumes 23 6 31.2GB 18.4GB (59%)
This aggregate figure is useful for deciding whether volume cleanup is worth prioritizing at all relative to other categories like build cache or unused images, but it still does not identify which specific volumes are responsible for the bulk of that reclaimable total, which is where the per-volume scripted approach above becomes necessary.
Distinguishing genuinely orphaned volumes from intentionally retained ones
Not every dangling volume is bloat in the sense of being safely removable; a volume intentionally kept around after a service was temporarily scaled down, or one retained deliberately as a recent backup source before being superseded by a newer one, is dangling by Docker's definition but not actually unwanted:
docker volume inspect pgdata-old --format '{{.CreatedAt}}'
Checking creation and, where available through labels, ownership or purpose metadata before removing any dangling volume avoids accidentally discarding something that was dangling for a legitimate, temporary reason rather than because it was genuinely abandoned.
Using labels to track volume purpose and ownership
Applying labels to volumes at creation time provides exactly the metadata that would otherwise be missing when later trying to decide whether a dangling volume is safe to remove, turning an otherwise opaque, randomly or generically named volume into something with documented context:
docker volume create --label project=my-api --label purpose=database-data pgdata
docker volume ls --filter "label=project=my-api"
A volume created with meaningful labels remains identifiable and attributable to its original purpose even long after the container that originally used it has been removed, which is considerably more useful during a later cleanup review than a bare volume name alone, especially for anonymous volumes whose names provide no information at all.
Removing dangling volumes from defunct Compose projects
A common, specific source of named (not just anonymous) dangling volume accumulation is a Compose project that was removed or relocated without ever running compose down against it first, leaving every volume it defined orphaned and disconnected, identifiable mainly by a naming pattern tied to the original project directory name:
docker volume ls --filter "name=oldproject_"
Reviewing volumes that match a naming pattern from a project no longer in active use is a reasonable, targeted way to identify this specific category of dangling volume, distinct from the more generic, randomly-named anonymous volumes covered elsewhere.
A safer cleanup workflow combining size and purpose review
Combining the size-calculation script with a review of each volume's labels, creation date, and naming pattern produces a cleanup workflow considerably safer than a blanket docker volume prune, since it surfaces both how much space is actually at stake and enough context to judge whether removal is appropriate for each specific case:
for v in $(docker volume ls -f dangling=true -q); do
size=$(docker run --rm -v "$v":/data alpine du -sh /data 2>/dev/null | cut -f1)
created=$(docker volume inspect "$v" --format '{{.CreatedAt}}')
echo "$v | size=$size | created=$created"
done
Reviewing this combined output before deciding what to remove is considerably more deliberate than a single, blanket pruning command, at the cost of more manual effort, which is a reasonable trade-off specifically for volumes, given the genuine risk of permanent data loss that a hasty, blanket removal carries.
Common mistakes
- Assuming all dangling volumes are negligible in size simply because Docker provides no size information for them by default, rather than actually measuring it directly.
- Removing dangling volumes in bulk without any review of their creation date, labels, or naming pattern, risking discarding something intentionally retained rather than genuinely abandoned.
- Not applying labels to volumes at creation time, leaving future cleanup decisions with no contextual information beyond a bare, often uninformative volume name.
- Overlooking named dangling volumes left behind by a defunct Compose project, focusing cleanup attention only on anonymous, randomly-named volumes.
- Relying solely on
docker system df's aggregate volume size figure without drilling down to identify which specific volumes are actually responsible for the bulk of that total.
Dangling volume bloat is harder to quantify than image or container bloat specifically because Docker provides no built-in per-volume size reporting, which makes a combination of scripted size calculation, label-based purpose tracking, and deliberate, individual review essential before any cleanup, given that the consequence of a mistaken removal here, permanent data loss, is considerably more severe than the consequence of mistakenly removing an unused image.