flowchart LR C["Container"] --> V["Volume<br/>/var/lib/docker/volumes/..."] C --> B["Bind mount<br/>any directory on the host"] C --> T["tmpfs<br/>host RAM"]
| Type | Where it lives | Use when |
|---|---|---|
| Volume | An area managed by Docker (/var/lib/docker/volumes/ on Linux) |
Persisting app data, databases — the preferred choice |
| Bind mount | Any path on the host | Mounting source code during development, host config files |
| tmpfs (Linux only) | RAM, never written to disk | Temporary or sensitive data you do not need to keep |
-v and --mount
The two syntaxes are equivalent; --mount is longer but more explicit:
docker run -d --name web -v site-data:/usr/share/nginx/html nginx:1.27
docker run -d --name web --mount type=volume,src=site-data,dst=/usr/share/nginx/html nginx:1.27
docker run -d --name web -v "$(pwd)"/html:/usr/share/nginx/html:ro nginx:1.27
docker run -d --name web --mount type=bind,source="$(pwd)"/html,target=/usr/share/nginx/html,readonly nginx:1.27
docker run -d --name cache --tmpfs /tmp nginx:1.27
Common traps
- Name or path?
-v html:/usr/share/nginx/html(no leading/) creates a named volume calledhtml, not a bind mount of thehtmlfolder. A bind mount needs an absolute path such as"$(pwd)"/html. - A bind mount hides whatever the image already had in the target directory. In contrast, an empty volume mounted on a directory with files gets the image content copied into it by Docker.
- tmpfs does not persist: stop the container and it is gone.
-vcreates a missing host directory for you;--mount type=bindfails instead, which catches typos in the path.- Add
:ro(orreadonly) when the container only needs to read.
Choosing between them
| Need | Mount type |
|---|---|
| Database files in production | Named volume |
| Live-reload source code while developing | Bind mount |
Host configuration file such as nginx.conf |
Bind mount, read-only |
| Scratch space or secrets that must never touch disk | tmpfs |
| Sharing data between containers on one host | Named volume |
Bind mounts depend on the host's directory layout, so they make a container less portable. Volumes work the same on every host and can use drivers for remote storage.
Platform details
- SELinux hosts (Fedora, RHEL): add
:z(shared) or:Z(private) to a bind mount so Docker relabels the files; without it the container gets permission errors. - Docker Desktop on macOS and Windows shares host folders into its Linux VM, so bind mounts are slower than on Linux. Keeping dependencies such as
node_modulesin a volume while bind-mounting only the source code speeds things up. - Mount propagation options (
rprivate,rshared) control whether mounts created inside the container appear on the host; they are rarely needed outside storage tools.
tmpfs options
--tmpfs /run:rw,size=64m,mode=1777 limits the size and sets permissions. Memory used by tmpfs counts against the container's memory limit.
Secrets and config files
Swarm and Compose can deliver secrets as files under /run/secrets/<name>, mounted from memory rather than baked into the image or passed in environment variables, which are easy to leak through docker inspect or crash logs. Kubernetes uses the same idea with Secret volumes.
Seeing what is mounted
docker inspect -f '{{json .Mounts}}' web lists each mount with its type, source, destination, and whether it is read-write. Checking this is the fastest way to debug "my file is not there" problems.