| |

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:

FieldMeaning
NameVolume name
DriverStorage driver
MountpointPath on the host
CreatedAtCreation timestamp
LabelsKey-value metadata
OptionsDriver options
Scopelocal 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

CommandPurpose
docker volume create nameCreate a volume
docker volume createCreate an anonymous volume
docker volume lsList volumes
docker volume inspect nameShow volume details
docker volume rm nameRemove a volume
docker volume pruneRemove unused volumes

Create Options

OptionPurpose
--driverStorage driver
--optDriver options
--labelKey-value metadata
--nameVolume name

List Filters

FilterEffect
dangling=trueUnused volumes
label=key=valueVolumes with label
driver=localVolumes with driver
name=patternVolumes by name

Inspect Fields

FieldMeaning
NameVolume name
DriverStorage driver
MountpointHost path
CreatedAtCreation time
LabelsMetadata
OptionsDriver options
Scopelocal or global

Prune Options

OptionEffect
-f, --forceSkip confirmation
--filter label=key=valuePrune by label
--filter all=truePrune all unused
--filter until=24hPrune 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

PitfallWhy It HappensFix
Volume not removedContainer still existsRemove container first
Volume removed accidentallyPruned without filterUse labels and filters
Data lostVolume prunedBack up before pruning
Anonymous volume orphanedNo nameUse named volumes
Volume not foundWrong namedocker volume ls
Driver options wrongNFS or cloud misconfiguredCheck --opt
Mount point inaccessiblePermissionsCheck 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

ItemValue
Createdocker volume create name
Create with labelsdocker volume create --label key=value name
Create with driverdocker volume create --driver local --opt ... name
Listdocker volume ls
List danglingdocker volume ls --filter dangling=true
Inspectdocker volume inspect name
Mount pointdocker volume inspect --format '{{.Mountpoint}}' name
Removedocker volume rm name
Prunedocker volume prune
Prune by labeldocker volume prune --filter label=key=value
Force prunedocker 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 the docker volume commands 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. The docker volume inspect command 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 prune removes dangling volumes. It does not remove volumes that are in use. It prompts for confirmation unless -f is 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 local driver 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 --driver and --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!