The core idea
A volume is a directory that Docker creates and manages, separate from any container. You mount it into a container at a path, and everything written there goes into the volume. Remove the container and the volume stays; mount it into a new container and the data is all there.
Create, write, read again
$ docker volume create notes-datanotes-data$ docker run --rm -v notes-data:/data alpine sh -c 'echo "written by container one" > /data/hello.txt'$ docker run --rm -v notes-data:/data alpine cat /data/hello.txtwritten by container one
Two containers, both deleted with --rm. The file lives on in the volume.
$ docker volume inspect notes-data[{"CreatedAt": "2026-11-02T20:30:51Z","Driver": "local","Mountpoint": "/var/lib/docker/volumes/notes-data/_data","Name": "notes-data","Scope": "local"...}]
The Mountpoint is a folder on the Docker host. On Linux you could look at it directly with sudo; on Docker Desktop it's
inside the Linux VM. Either way, treat it as Docker's: go through containers, not the folder.
Two ways to write the same mount
# Short: source:destination[:options]
docker run -v notes-data:/data alpine ...
# Long: explicit key=value pairs, easier to read in scripts
docker run --mount type=volume,src=notes-data,dst=/data alpine ...Add :ro (short) or ,readonly (long) to mount read-only:
$ docker run --rm --mount type=volume,src=notes-data,dst=/data,readonly alpine \sh -c 'cat /data/hello.txt; echo nope > /data/x'written by container onesh: can't create /data/x: Read-only file system
Named vs anonymous volumes
If an image declares VOLUME /some/path and you don't mount anything there, Docker creates an anonymous volume
with a random name. The official Postgres image does this:
$ docker run -d --name pg -e POSTGRES_PASSWORD=x postgres:18$ docker inspect -f '{{range .Mounts}}{{.Type}} {{.Name}} -> {{.Destination}}{{end}}' pgvolume 0eb4d36e933db0246a63ef9175338b25d3d8940343647a3981762d657c662acd -> /var/lib/postgresql
Your data is safe-ish, but in a volume nobody will recognise. Recreate the container and you get a new anonymous
volume and an empty database; the old one sits there orphaned. docker rm -v and docker run --rm delete anonymous
volumes along with the container. Always name volumes for data you care about.
Pre-populated volumes
Mount an empty named volume at a path that already has files in the image, and Docker copies those files into the volume first:
$ docker run --rm -v site:/usr/share/nginx/html nginx:alpine ls /usr/share/nginx/html50x.htmlindex.html$ docker run --rm -v site:/x alpine ls /x50x.htmlindex.html
The second container is plain Alpine, but the volume already contains nginx's files. This only happens for empty volumes, never for bind mounts (04.03 Bind mounts).
Backing up a volume
A volume is just files, so back it up with a throwaway container that mounts it next to a folder from your machine:
$ docker run --rm -v notes-data:/data -v "$PWD":/backup alpine \tar czf /backup/notes-data.tgz -C /data .$ tar tzf notes-data.tgz././hello.txt
To restore, run the same thing with tar xzf into a new volume. For databases, prefer the database's own dump tool,
because copying the files of a running database can capture a half-written state (04.05 Project: persist Postgres).
Housekeeping
| Command | Does |
|---|---|
docker volume ls | list volumes |
docker volume ls -f dangling=true | volumes no container uses |
docker volume rm NAME | delete one (fails if a container uses it) |
docker volume prune | delete unused anonymous volumes; add -a to include named ones |
docker system df -v | size of each volume |
Three containers mount the same named volume at /data. One deletes /data/report.csv. What do the other two see?
Create a volume, write to it from one container, read it from another, then back it up to a .tgz on your machine. Delete the volume, restore it from the archive into a new volume, and read the file once more.
STUCK? ▸
Empty volume when you expected files: check the volume name is spelled the same in both commands. -v notes-dat:/data silently creates a new, empty volume called notes-dat.
Recap
Interview questions
What's the difference between a named volume and an anonymous volume?
How would you back up and restore data stored in a Docker volume?