Create, Inspect and Remove Docker Volumes Safely

A container gets recreated, its data vanishes, and the postmortem always comes back to a Docker volume nobody named or tracked. This gives you a repeatable way to create a volume, confirm its driver and mountpoint, find it later, and remove it when it is genuinely disposable. The examples use Docker Community Edition CLI 29.8.1, installed here as package docker-ce-cli version 5:29.8.1-1~ubuntu.24.04~noble.

Allow about 15 minutes. You need a shell, a working Docker daemon and permission to use it. These commands operate on the Docker daemon's volume store, not on an ordinary directory in the current folder. Creating and inspecting a volume is normally unprivileged when your account already has Docker access. Use sudo only if your host deliberately requires it; adding an account to the Docker group is a separate security decision.

Checkpoint: begin with a harmless inventory command. It changes nothing.

$ docker volume ls
DRIVER    VOLUME NAME

Your list will contain different names. An empty list is also a valid result.

1. Create a named volume

Choose a name that says what the data is for. A named volume is easier to identify and remove than an automatically generated name.

$ docker volume create app-data
app-data

The default driver is local. You can make that choice explicit, and attach metadata that helps later filtering:

$ docker volume create \
    --driver local \
    --label 'com.example.owner=platform' \
    app-data
app-data

If app-data already exists, Docker returns its name rather than creating a second volume. It does not retrofit the new label onto that existing volume. Use a different name such as app-data-test, or remove the test volume only after confirming it contains no required data, when you need to test creation options.

Docker volumes persist independently of a container's life cycle. Removing a container does not remove its volumes, which is useful for database data but also makes abandoned volumes easy to forget.

2. Find the volume without scanning the whole list

List only the names that match a name filter:

$ docker volume ls --filter 'name=app-data'
DRIVER    VOLUME NAME
local     app-data

For scripts, use --quiet so the output is only the volume name:

$ docker volume ls --quiet --filter 'name=app-data'
app-data

The name filter is a search filter, not a guarantee that one exact volume exists. Treat its output as a list. Other documented filters include driver, label and dangling. Multiple filters can be supplied when you need to narrow an inventory.

Checkpoint: if the expected name is absent, stop here. Check the Docker context and daemon you are connected to before creating a duplicate volume in the wrong environment.

3. Inspect identity and storage details

Inspect returns a JSON array by default. That is useful for complete diagnostics, but a format template is easier to read in a shell:

$ docker volume inspect --format '{{.Name}} {{.Driver}} {{.Mountpoint}}' app-data
app-data local /var/lib/docker/volumes/app-data/_data

The exact mountpoint depends on the daemon host and its storage configuration. Do not assume that the path is on the machine where you typed the command if your Docker client talks to a remote daemon. The template fields shown here are present in the installed command's output for a local volume.

To see all fields, omit --format:

$ docker volume inspect app-data
[
    {
        "CreatedAt": "...",
        "Driver": "local",
        "Labels": {
            "com.example.owner": "platform"
        },
        "Mountpoint": "/var/lib/docker/volumes/app-data/_data",
        "Name": "app-data",
        "Options": {},
        "Scope": "local"
    }
]

Values such as the creation time and mountpoint are host-specific, so the ellipsis above is illustrative rather than output to copy. Inspect is read-only. It does not mount the volume into a container or alter its contents.

4. Use the volume from a container

A volume becomes useful when a container mounts it at an absolute path inside the container. This small check writes no application data; it creates the mount and lists the empty directory:

$ docker run --rm --mount source=app-data,target=/data busybox ls -la /data
total 8
drwxr-xr-x    2 root     root          4096 ... .
drwxr-xr-x    1 root     root          4096 ... ..

The --rm option removes the short-lived container after it exits. It does not remove app-data. Multiple containers can use the same volume, including at the same time, but read and write coordination remains the application's responsibility.

Common trap: a container path such as data is not a valid relative mount point. Use an absolute path such as /data. Also remember that the volume is managed by Docker; deleting or replacing a container is not a backup strategy.

5. Remove one volume only after checking its users

Removal is destructive. Anything stored in the volume becomes unavailable through Docker after removal, and recovery is not provided by the command. Before removing a real volume, identify containers that use it and confirm that its data is backed up or disposable.

For the empty test volume created in this guide, the command is:

$ docker volume rm app-data
app-data

If a container is using the volume, Docker normally refuses the removal. Do not reach for --force as a first response. Stop or remove the dependent container deliberately, verify that its data is safe, then retry. The exact container command depends on how that container was deployed, so do not use a guessed container name in a production script.

Undo for an accidental removal is not another Docker volume command. Restore the data from your backup into a newly created volume, then update the deployment to use that volume. If you have not removed it yet, leave it in place and record its inspected name and driver instead.

6. Prune only with a written scope

docker volume prune removes unused local volumes. By default it removes unused anonymous volumes; --all broadens the action to all unused volumes. This is a destructive, service-affecting boundary: a volume can be unused by a running container and still contain data needed for a future deployment.

Preview the candidate set first:

$ docker volume ls --filter 'dangling=true'
DRIVER    VOLUME NAME

Use a label filter to restrict a cleanup policy you have designed in advance. Only approve the final command after reviewing the names:

$ docker volume prune --filter 'label=com.example.lifecycle=temporary'
WARNING! This will remove all local volumes not used by at least one container.
Are you sure you want to continue? [y/N]

Do not use --force in a copied cleanup snippet unless the selection and recovery plan are already tested. The prompt is a useful interruption. There is no general undo command for a pruned volume.

7. Separate local volumes from driver-specific configuration

The volume subcommand also accepts --driver and repeated --opt values at creation time. Those options are passed to the selected driver and their meaning varies. The built-in Linux local driver accepts options similar to the Linux mount command, but a driver-specific example should come from that driver's documentation and storage design. Do not copy a tmpfs, device or network-filesystem option into a production command without checking its data-loss and host-availability consequences.

Checkpoint: before handing a volume to an application, confirm three things with docker volume inspect: the name is the one you intended, the driver is expected, and the mountpoint or driver options fit the host where the daemon runs.

Done means