skip to content

Bind Mounts, Volumes & tmpfs

The three ways storage gets into a container - a host-coupled bind mount, a Docker-managed named volume, and in-memory tmpfs - and the -v and --mount syntaxes that create them. A standard comparison with real portability and data-loss consequences.

part ofDockeroverview, primer and where to startread it →
on this pageshow

questions

6

Docker can attach storage to a container as a bind mount, a named volume, or a tmpfs mount. How do these three differ, and when would you reach for each?

level: juniorimportance: must knowfreq 78%

answer

  1. bind = host path, you manage it
  2. volume = Docker manages, survives docker rm
  3. empty volume pre-populated from image; bind mount hides it
  4. tmpfs = RAM only, Linux, dies on stop
  5. all three bypass copy-on-write

basics

~20 s

A bind mount maps a host path into the container — good for local source code and config. A named volume is Docker-managed storage that outlives containers — good for databases and app data. A tmpfs mount lives only in RAM — good for scratch files and secrets.

solid answer

~60 s

All three replace what the image has at a container path, but the backing store differs. - **Bind mount** (`-v /host/path:/in/container`): a specific host directory or file. You control the exact location; Docker manages nothing. Best for development source code, config files and certificates mounted read-only. It couples the container to the host layout and gives it real host filesystem access, so it is a poor fit for production data. - **Named volume** (`-v mydata:/var/lib/postgresql/data`): storage Docker creates and tracks by name, stored under Docker's data root with the built-in `local` driver. It survives `docker rm`, is portable across hosts and Compose files, can be backed by plugin drivers, and an empty one is pre-populated from the image's content at that path. This is the default choice for persistent application data. - **tmpfs** (`--tmpfs /tmp`): RAM-backed, Linux-only, never written to the container's writable layer or to disk, and destroyed when the container stops. Best for scratch space and short-lived sensitive material. All three bypass the copy-on-write layer, so writes are faster than writing into the container's own filesystem.

code

bash · 9 lines
bash
# bind mount: an exact host directory
docker run -v /home/dev/app:/app node:22 npm run dev

# named volume: Docker-managed, survives container removal
docker volume create pgdata
docker run -v pgdata:/var/lib/postgresql/data postgres:17

# tmpfs: RAM only, gone when the container stops
docker run --tmpfs /tmp:size=64m alpine sh

go deeper

for a junior

Be able to name all three, give one everyday use case each, and state clearly that a named volume survives container removal while tmpfs does not survive a stop.

for a middle

Add the mechanics: mounts bypass the copy-on-write layer, an empty named volume is pre-populated from the image while a bind mount hides image content, and anonymous volumes are the ones that pile up.

for a senior

Frame it as an operational choice — volumes for state you back up and upgrade around, bind mounts only for host-owned config and dev loops, tmpfs to keep secrets and scratch off disk — and mention the Docker Desktop performance difference.

for a principal

Talk about the policy: state belongs in named volumes or external services so hosts stay disposable, bind mounts of host paths are an escape hatch that has to be justified and audited (especially the Docker socket), and standardising this is what makes workloads portable to orchestrators later.

## Why mounts exist at all A container's own filesystem is a stack of read-only image layers plus one thin writable layer on top, managed by a storage driver (overlay2 on most Linux hosts). That writable layer has two problems. First, it is tied to the container: `docker rm` destroys it, so anything written there is gone. Second, copy-on-write is slow for write-heavy workloads — modifying a large file first copies the whole file up out of the image layer. A mount solves both. When Docker starts a container it builds a private mount namespace, and for each requested mount it mounts something else over the given path. Reads and writes at that path go straight to the backing filesystem, completely bypassing the union filesystem and the container lifecycle. ## Bind mounts A bind mount attaches an existing host path — a directory or a single file — to a path inside the container. The host path is absolute and fully under your control; Docker stores no metadata about it and `docker volume ls` will never show it. Strengths: you can see and edit the files with normal host tools, which makes it the natural fit for mounting a source tree into a dev container so edits appear immediately, or for injecting `nginx.conf`, TLS certs or a `.env` file read-only. Weaknesses: it hard-codes host layout into your run command, which breaks portability across machines and CI. It is also the biggest foot-gun for security — a bind mount of `/`, `/etc` or `/var/run/docker.sock` effectively hands the host to the container. Ownership is host ownership, so the container's user id must line up with the host file owner (a topic in its own right). ## Named volumes A named volume is storage Docker creates, names and tracks. With the default `local` driver its data lives under Docker's data root (typically `/var/lib/docker/volumes/<name>/_data` on Linux), but you should treat that path as an implementation detail and go through `docker volume` commands. Properties that matter in interviews: - **Lifecycle independence.** Removing the container does not remove the volume; only `docker volume rm` or `docker volume prune` does. Data survives image upgrades — that is exactly how you upgrade a database container. - **Pre-population.** If the volume is empty the first time it is mounted, Docker copies whatever the image already has at that container path into the volume. A bind mount never does this; it simply hides the image content. - **Portability.** The run command mentions only a name, so the same Compose file works on a laptop, a CI runner and a server. - **Pluggable backing.** Driver options let a volume be backed by NFS or a plugin instead of a local directory. - **Speed on Docker Desktop.** On macOS and Windows, volumes live inside the Linux VM's own disk, while bind mounts cross a host↔VM filesystem bridge. For anything IO-heavy the volume is dramatically faster. A related form is the **anonymous volume**: same storage, no name — created by a Dockerfile `VOLUME` instruction or by `-v /path/in/container` with no source. It gets a random hex ID, is easy to lose track of, and is the usual cause of "why is my disk full of volumes". ## tmpfs mounts A tmpfs mount is a RAM-backed filesystem mounted into the container. Nothing is written to the image, the writable layer, or a host directory. When the container stops, the content is gone. Use it for scratch files, caches you never want to persist, and short-lived credentials you do not want landing on disk. It is Linux-containers-only, cannot be shared between containers, and its content counts against the container's memory — an unbounded tmpfs can get the container OOM-killed, so set a size. ## Choosing - Persistent application state (database files, uploaded content, message-broker data) → **named volume**. - Live source code during development, host config injected read-only, host log directories → **bind mount**. - `/tmp`, `/run`, scratch, in-memory secrets, and the writable holes you punch in a `--read-only` container → **tmpfs**. A useful default: if the container itself owns the data, use a volume; if the host owns the data, use a bind mount; if nobody should own it after the process exits, use tmpfs.

  • Does `docker rm mycontainer` delete the data in a named volume the container used?
    No. Named volumes have a lifecycle independent of any container, so the data stays and can be mounted into a replacement container. That is what makes in-place image upgrades of stateful services safe. `docker rm -v` does remove *anonymous* volumes attached to that container, and `docker volume rm` or `docker volume prune` removes named ones explicitly.
  • Where does a named volume actually live on a Linux host, and should you edit it there?
    With the default `local` driver it is a directory under Docker's data root, usually `/var/lib/docker/volumes/<name>/_data`. You can read it as root, but treat it as an implementation detail: another driver puts the data somewhere else entirely, and poking at it directly bypasses permissions and can confuse a running container. Prefer a throwaway container that mounts the volume for backup or inspection.
  • Why is a bind mount of a source tree slow on Docker Desktop but fast on a Linux server?
    On a Linux server the container shares the host kernel and the bind mount is a native kernel bind — essentially free. On macOS and Windows the containers run inside a Linux VM, so a host bind mount has to be shared across the VM boundary over a file-sharing layer such as VirtioFS, which adds per-operation latency. Named volumes live inside the VM's disk and avoid that crossing.

A bind mount is a window cut into the host's own filing cabinet; a named volume is a storage locker the building manages and hands you by number; tmpfs is a whiteboard wiped clean when you leave the room.

saying these in an interview costs you the question

  • Saying bind mounts and named volumes are "the same thing with different syntax".
  • Claiming volume data is deleted when the container is removed.
  • Assuming tmpfs content survives a container restart, or that it is written to disk somewhere.
  • Believing you must add a `VOLUME` instruction to the Dockerfile for data to persist — that only creates an anonymous volume you did not name.
  • Saying a bind mount over a non-empty image directory merges the two sets of files, rather than hiding the image content.

context

open as a page

A Docker image already contains files at `/app/node_modules`. What does the container see at that path if you mount an empty named volume there, versus if you mount an empty host directory there as a bind mount?

level: middleimportance: should knowfreq 50%

basics

~20 s

An empty named volume is pre-populated: Docker copies the image's files at that path into the volume on first use, so the container still sees them. An empty bind mount is not — it simply hides the image content, and the container sees an empty directory.

open as a page

When would you attach a `tmpfs` mount to a Docker container instead of a volume or a bind mount, and what limitations does a tmpfs mount have?

level: middleimportance: should knowfreq 40%

basics

~20 s

Use tmpfs when data must never touch disk or persist: scratch files, caches, short-lived credentials, and the writable paths a --read-only container still needs. Limits: Linux containers only, not shareable, gone on stop, and it consumes the container's memory — always set a size.

open as a page

The `docker run` command accepts both the `-v`/`--volume` flag and the `--mount` flag for attaching storage. What are the practical differences between the two, and which would you use?

level: middleimportance: should knowfreq 55%

basics

~20 s

-v is a short colon-separated triple; --mount is explicit key=value pairs with type=. The dangerous difference: -v silently creates a missing host directory (empty, root-owned), while --mount type=bind fails fast. --mount is also more readable and exposes more options.

open as a page

A team wants edits made in a developer's editor to appear instantly inside a running Docker container so the app hot-reloads. How would you set that up, and what problems does that arrangement typically cause?

level: seniorimportance: should knowfreq 42%

basics

~20 s

Bind-mount the project directory into the container and run the framework's watch mode. Then handle the fallout: shadow build output and dependency directories with volumes, expect slow IO and missed file-change events on Docker Desktop, and never ship this setup — production images copy the code in.

open as a page

How would you run a Docker container whose filesystem is immutable except for the few paths that genuinely need to be written, and what does marking an individual mount read-only actually enforce?

level: seniorimportance: should knowfreq 45%

basics

~20 s

Run with --read-only to make the root filesystem immutable, then add back exactly what is needed: sized tmpfs mounts for /tmp and /run, a named volume for real data, and :ro bind mounts for config and certs. A read-only mount blocks writes from that container only — the host and other containers can still change the data.

open as a page