Docker 27 🐳 Managing Docker Volumes: docker volume create, inspect, ls, and prune
A volume is a Docker-managed storage location that exists outside the container’s lifecycle. It is created, listed, inspected, and removed through the docker volume command family. Unlike a bind mount, which is a host path that Docker maps into a container, a volume is a first-class object with its own name, metadata, and driver. Docker tracks it, and the docker volume commands are how you interact with that tracking. This chapter covers the lifecycle of a volume: creating it, listing it, inspecting its details, removing it, and pruning the ones that are no longer used.
Key point: A volume exists independently of any container. It is created with docker volume create, listed with docker volume ls, inspected with docker volume inspect, removed with docker volume rm, and bulk-removed with docker volume prune. A volume is not deleted when the container using it is removed. It must be deleted explicitly, or it persists until pruned.
Why volume management matters
The orphan problem. When a container is removed, its volumes remain. This is by design—the data is not lost when the container that produced it is discarded. But over time, the host accumulates volumes from containers that no longer exist. A development machine that has run dozens of database containers may have dozens of orphaned volumes, each consuming disk space. docker volume prune removes the ones that are not in use.
The identification problem. A volume is referenced by name. To know what a volume contains, which container created it, and where it is stored on the host, docker volume inspect is the tool. It returns the volume’s name, driver, mount point, labels, and options. This is the information needed for backup, migration, and troubleshooting.
The driver problem. A volume is created with a driver. The default is local, which stores the data on the Docker host. Other drivers—nfs, rexray, cloud-specific plugins—store the data elsewhere. The driver is specified at creation time with --driver and --opt, and it determines where the data lives and how it is accessed.
The label problem. Volumes can be labeled at creation with --label. Labels are key-value pairs that can be used to organize, filter, and automate volume management. docker volume ls --filter label=env=production lists only the volumes with that label. docker volume prune --filter label=env=dev removes only the development volumes.
The lifecycle problem. A volume’s lifecycle is independent of the container’s. The container can be removed and recreated without affecting the volume. This is the feature that makes stateful containers possible: the container is disposable, and the volume is the state. Managing the volume’s lifecycle is managing the state’s lifecycle.
a. Creating volumes
A volume is created with docker volume create. The name is optional; if omitted, Docker generates a random name.
docker volume create mydata
docker volume create
The first command creates a volume named mydata. The second creates an anonymous volume with a generated name. Anonymous volumes are created automatically when a container declares a VOLUME in its Dockerfile and the user does not specify a mount.
A volume can be created with a driver and options:
docker volume create --driver local \
--opt type=nfs \
--opt o=addr=10.0.0.10,rw \
--opt device=:/exports/data \
nfs_data
The --driver local uses the local driver, and the --opt flags configure it to mount an NFS share. The --opt type=nfs specifies the filesystem type, o=addr=... specifies the mount options, and device=:/exports/data specifies the NFS export. The resulting volume mounts the NFS share when a container uses it.
A volume can be created with labels:
docker volume create --label env=production --label app=db pgdata
The labels are metadata. They are visible in docker volume inspect and can be used as filters in docker volume ls and docker volume prune.
A volume can also be created implicitly by running a container with a volume mount:
docker run -d -v mydata:/data alpine sleep 3600
If mydata does not exist, Docker creates it. This is the most common way volumes come into existence. The explicit docker volume create is used when the volume needs specific driver options or labels before it is mounted.
b. Listing and inspecting volumes
The docker volume ls command lists all volumes on the host.
docker volume ls
The output shows the driver and the volume name. The list includes volumes created explicitly and volumes created implicitly by containers. It includes volumes that are in use and volumes that are orphaned.
The list can be filtered:
docker volume ls --filter dangling=true
docker volume ls --filter label=env=production
docker volume ls --filter driver=local
The dangling=true filter lists volumes that are not used by any container. This is the list that docker volume prune would remove. The label filter lists volumes with a specific label. The driver filter lists volumes created with a specific driver.
The format can be customized with --format:
docker volume ls --format "{{.Name}}: {{.Driver}}"
docker volume ls --format "table {{.Name}}\t{{.Driver}}\t{{.Mountpoint}}"
The format uses Go template syntax and the volume’s fields: Name, Driver, Mountpoint, Labels, Scope.
The docker volume inspect command shows the details of a volume:
docker volume inspect mydata
The output is JSON. The fields are:
| Field | Meaning |
|---|---|
Name | Volume name |
Driver | Storage driver |
Mountpoint | Path on the host |
CreatedAt | Creation timestamp |
Labels | Key-value metadata |
Options | Driver options |
Scope | local or global |
The mountpoint is the host path where the data is stored. For a local volume, it is /var/lib/docker/volumes/mydata/_data. This is the path that a backup tool would read, or that a bind mount would use if the volume needs to be accessed directly.
The --format flag extracts specific fields:
docker volume inspect --format '{{.Mountpoint}}' mydata
docker volume inspect --format '{{json .Labels}}' mydata
Multiple volumes can be inspected by name:
docker volume inspect vol1 vol2 vol3
c. Removing and pruning volumes
The docker volume rm command removes a volume by name.
docker volume rm mydata
The volume must not be in use by any container. If a container is using it, even a stopped container, the removal fails with an error. The container must be removed first, or the volume must be pruned.
Multiple volumes can be removed:
docker volume rm vol1 vol2 vol3
The docker volume prune command removes all volumes that are not used by any container.
docker volume prune
The command prompts for confirmation before removing. The -f or --force flag skips the prompt:
docker volume prune -f
Pruning is the cleanup mechanism. It removes the volumes that were created by containers that have since been removed. It does not remove volumes that are in use by a container, even a stopped one.
The prune can be filtered:
docker volume prune --filter label=env=dev
docker volume prune --filter all=true
The label filter removes only the volumes with a specific label. The all=true filter removes all unused volumes regardless of labels. Without filters, prune removes all unused volumes.
A volume that is in use by a container is not removed by prune. The container must be removed first. This is a safety measure: the data is not lost because a container happened to be stopped.
The docker volume prune command is the counterpart to docker container prune and docker image prune. Together they clean up the Docker host. The volumes are the ones that hold data, so pruning them is the most consequential. The prompt is there for a reason.
Complete Example Session
# ============================================
# PART 1: CREATE A VOLUME
# ============================================
docker volume create mydata
docker volume ls
# ============================================
# PART 2: CREATE A VOLUME WITH LABELS
# ============================================
docker volume create --label env=production --label app=db pgdata
docker volume inspect pgdata
# ============================================
# PART 3: LIST VOLUMES
# ============================================
docker volume ls
docker volume ls --format "table {{.Name}}\t{{.Driver}}\t{{.Mountpoint}}"
# ============================================
# PART 4: FILTER BY LABEL
# ============================================
docker volume ls --filter label=env=production
docker volume ls --filter label=app=db
# ============================================
# PART 5: INSPECT A VOLUME
# ============================================
docker volume inspect mydata
docker volume inspect --format '{{.Mountpoint}}' mydata
# ============================================
# PART 6: MOUNT THE VOLUME
# ============================================
docker run -d --name db \
-v pgdata:/var/lib/postgresql/data \
postgres:18
# ============================================
# PART 7: TRY TO REMOVE A VOLUME IN USE
# ============================================
docker volume rm pgdata
# Error: volume is in use
# ============================================
# PART 8: REMOVE THE CONTAINER AND THE VOLUME
# ============================================
docker stop db && docker rm db
docker volume rm pgdata
docker volume ls
# ============================================
# PART 9: PRUNE UNUSED VOLUMES
# ============================================
docker volume prune
docker volume prune -f
# ============================================
# PART 10: PRUNE WITH FILTER
# ============================================
docker volume prune --filter label=env=dev
docker volume prune --filter all=true
The ten parts covered creating a volume, creating with labels, listing, filtering by label, inspecting, mounting, attempting to remove a volume in use, removing the container and volume, pruning unused volumes, and pruning with filters.
Quick Reference
Volume Commands
| Command | Purpose |
|---|---|
docker volume create name | Create a volume |
docker volume create | Create an anonymous volume |
docker volume ls | List volumes |
docker volume inspect name | Show volume details |
docker volume rm name | Remove a volume |
docker volume prune | Remove unused volumes |
Create Options
| Option | Purpose |
|---|---|
--driver | Storage driver |
--opt | Driver options |
--label | Key-value metadata |
--name | Volume name |
List Filters
| Filter | Effect |
|---|---|
dangling=true | Unused volumes |
label=key=value | Volumes with label |
driver=local | Volumes with driver |
name=pattern | Volumes by name |
Inspect Fields
| Field | Meaning |
|---|---|
Name | Volume name |
Driver | Storage driver |
Mountpoint | Host path |
CreatedAt | Creation time |
Labels | Metadata |
Options | Driver options |
Scope | local or global |
Prune Options
| Option | Effect |
|---|---|
-f, --force | Skip confirmation |
--filter label=key=value | Prune by label |
--filter all=true | Prune all unused |
--filter until=24h | Prune older than duration |
Best Practices
✅ Do This:
# Name your volumes explicitly
docker volume create postgres_data # ✅
# Label volumes for organization
docker volume create --label env=prod --label app=db pgdata # ✅
# Inspect a volume before removing it
docker volume inspect mydata # ✅
# Remove the container before removing the volume
docker stop db && docker rm db && docker volume rm pgdata # ✅
# Prune only what you intend to remove
docker volume prune --filter label=env=dev # ✅
# Back up a volume before pruning
docker run --rm -v mydata:/src:ro -v $(pwd):/bk alpine tar czf /bk/data.tar.gz -C /src . # ✅
# Use --format for scripting
docker volume ls --format "{{.Name}}" --filter dangling=true # ✅
❌ Don’t Do This:
# Don't remove a volume while a container is using it
docker volume rm pgdata # fails if in use # ❌
# Don't prune without checking what will be removed
docker volume prune -f # no confirmation # ⚠️
# Don't forget that prune does not remove in-use volumes
# The container must be removed first # ⚠️
# Don't use anonymous volumes for data that matters
docker run -v /data postgres # random name, hard to manage # ⚠️
# Don't rely on volume names that might collide
docker volume create data # too generic # ⚠️
# Don't prune volumes that are still needed
docker volume prune --filter all=true # removes everything unused # ❌
# Don't forget that a stopped container still holds the volume
docker stop db # volume is still in use # ⚠️
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| Volume not removed | Container still exists | Remove container first |
| Volume removed accidentally | Pruned without filter | Use labels and filters |
| Data lost | Volume pruned | Back up before pruning |
| Anonymous volume orphaned | No name | Use named volumes |
| Volume not found | Wrong name | docker volume ls |
| Driver options wrong | NFS or cloud misconfigured | Check --opt |
| Mount point inaccessible | Permissions | Check UID/GID |
Real-World Examples
1. Create a Named Volume
docker volume create app_data
2. Create with Labels
docker volume create --label env=prod --label app=web web_data
3. Create an NFS Volume
docker volume create --driver local \
--opt type=nfs \
--opt o=addr=10.0.0.10,rw \
--opt device=:/exports/data \
nfs_data
4. List All Volumes
docker volume ls
5. List Dangling Volumes
docker volume ls --filter dangling=true
6. Inspect a Volume
docker volume inspect app_data
7. Get the Mountpoint
docker volume inspect --format '{{.Mountpoint}}' app_data
8. Remove a Volume
docker volume rm app_data
9. Prune Unused Volumes
docker volume prune -f
10. Prune by Label
docker volume prune --filter label=env=dev
Visual
Volume Lifecycle
┌─────────────────────────────────────────────────────────────┐
│ docker volume create mydata │
│ │ │
│ ▼ │
│ Volume exists on host │
│ /var/lib/docker/volumes/mydata/_data │
│ │ │
│ ▼ │
│ docker run -v mydata:/data myapp │
│ Container mounts the volume │
│ │ │
│ ▼ │
│ docker rm container │
│ Container is removed │
│ Volume still exists │
│ │ │
│ ▼ │
│ docker volume rm mydata │
│ Volume is removed │
│ │
│ The volume outlives the container. │
│ │
└─────────────────────────────────────────────────────────────┘
Volume States
┌─────────────────────────────────────────────────────────────┐
│ IN USE │
│ Mounted by at least one container (running or stopped). │
│ Cannot be removed. │
│ Not removed by prune. │
│ │
├─────────────────────────────────────────────────────────────┤
│ │
│ DANGLING │
│ Not mounted by any container. │
│ Can be removed with docker volume rm. │
│ Removed by docker volume prune. │
│ │
├─────────────────────────────────────────────────────────────┤
│ │
│ ANONYMOUS │
│ Created implicitly by a container. │
│ Has a generated name. │
│ Often dangling after the container is removed. │
│ │
└─────────────────────────────────────────────────────────────┘
Volume vs Bind Mount Directory
┌─────────────────────────────────────────────────────────────┐
│ VOLUME │
│ │
│ /var/lib/docker/volumes/mydata/_data │
│ Managed by Docker. │
│ Referenced by name. │
│ Portable across hosts. │
│ │
├─────────────────────────────────────────────────────────────┤
│ │
│ BIND MOUNT │
│ │
│ /home/user/app │
│ Managed by you. │
│ Referenced by host path. │
│ Depends on host layout. │
│ │
└─────────────────────────────────────────────────────────────┘
Prune Behavior
┌─────────────────────────────────────────────────────────────┐
│ BEFORE PRUNE │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ vol1 (in use by container A) KEPT │ │
│ │ vol2 (dangling) REMOVED │ │
│ │ vol3 (in use by container B) KEPT │ │
│ │ vol4 (dangling) REMOVED │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ AFTER docker volume prune │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ vol1 (in use) KEPT │ │
│ │ vol3 (in use) KEPT │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ In-use volumes are never removed by prune. │
│ │
└─────────────────────────────────────────────────────────────┘
Summary
| Item | Value |
|---|---|
| Create | docker volume create name |
| Create with labels | docker volume create --label key=value name |
| Create with driver | docker volume create --driver local --opt ... name |
| List | docker volume ls |
| List dangling | docker volume ls --filter dangling=true |
| Inspect | docker volume inspect name |
| Mount point | docker volume inspect --format '{{.Mountpoint}}' name |
| Remove | docker volume rm name |
| Prune | docker volume prune |
| Prune by label | docker volume prune --filter label=key=value |
| Force prune | docker volume prune -f |
Key takeaways:
- A volume is a first-class object with a name, driver, and metadata. It is created with
docker volume create, and it exists independently of any container. Docker tracks it, and thedocker volumecommands are how you interact with it. - The volume’s mount point is on the host. For a local volume, it is
/var/lib/docker/volumes/<name>/_data. Thedocker volume inspectcommand returns this path, which is what a backup tool or a direct access needs. - A volume in use cannot be removed. The container must be removed first, even if the container is stopped. The volume is held by the container’s mount, and the removal fails until the mount is released.
docker volume pruneremoves dangling volumes. It does not remove volumes that are in use. It prompts for confirmation unless-fis used. Filters can narrow the prune to specific labels or drivers.- Labels are the organization mechanism. A volume can be created with
--label, listed with--filter label=..., and pruned with--filter label=.... This is how volumes are grouped and managed in a multi-application host. - Drivers determine where the data lives. The default
localdriver stores the data on the host. Other drivers store it on NFS, cloud storage, or a storage system. The driver is specified at creation with--driverand--opt. - The volume’s lifecycle is independent of the container’s. The container is disposable; the volume is the state. Removing the container does not remove the volume. Removing the volume is an explicit action, and it should be taken with the same care as deleting a file.
Remember: A volume is the boundary between the ephemeral container and the persistent world. The container’s writable layer is discarded when the container is removed; the volume is not. The docker volume commands are the management interface: create to make a volume, inspect to see its details, list to find it, remove to delete it, and prune to clean up the ones that are no longer needed. The commands are simple, but the decisions they represent are not. Pruning a volume is deleting data. Removing a volume in use is impossible, which is a safety net. Backing up a volume before pruning is the precaution. Manage the volumes deliberately, and the stateful containers that depend on them will be predictable.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!