beginner~4h

Storage: Volumes, Bind Mounts & tmpfs

Container filesystems are ephemeral by design — the writable layer disappears with the container. Docker provides three mechanisms for data that needs to outlive a container or be shared with the host

Container filesystems are ephemeral by design — the writable layer disappears with the container. Docker provides three mechanisms for data that needs to outlive a container or be shared with the host: volumes (Docker-managed, portable), bind mounts (direct host path mapping), and tmpfs mounts (in-memory, never touches disk).

Volumes are the recommended mechanism for persistent application data (databases, message broker state) because Docker manages their lifecycle, location, and backup tooling independently of any specific host path layout.

Bind mounts map an exact host directory/file into the container — ideal for local development (live code reload) and for exposing host resources like /etc/letsencrypt certs, but they tie the container to that host's specific filesystem layout, hurting portability.

tmpfs mounts store data only in host memory (RAM), never written to disk, and are wiped when the container stops — useful for secrets or scratch space that must never persist.

  • Named volumes are created and managed entirely by Docker under /var/lib/docker/volumes//_data on Linux; a volume driver plugin can redirect this to network storage (NFS, EBS, Azure Files, etc.).

  • When you mount a volume into a container, Docker bind-mounts that managed directory into the container's mount namespace at the target path you specify — the container sees a normal directory.

  • Bind mounts skip Docker's volume management entirely: the daemon performs a direct Linux bind mount syscall, mapping an existing host path directly into the container's namespace, with the host's actual permissions and SELinux/AppArmor context applying.

  • tmpfs mounts are implemented via the Linux tmpfs filesystem, an in-memory filesystem; data written there counts against the container's memory limit (if set) and is never flushed to the host disk.

  • Volume drivers (local, nfs, rexray, cloud-specific plugins) abstract the actual storage backend; docker volume create --driver lets you back a volume with anything from local disk to a remote NFS share, transparent to the container.

  • Anonymous volumes (declared with just a container path, no name) are automatically created and are the most common source of accidental hidden state — Docker auto-generates a random name for them.

  • docker volume create pgdata — Docker creates a managed directory under /var/lib/docker/volumes/pgdata/_data.

  • docker run -v pgdata:/var/lib/postgresql/data postgres:16 — Docker bind-mounts that managed directory into the container at /var/lib/postgresql/data.

  • Postgres writes its data files; they physically land in the host-side managed directory, completely independent of the container's own writable layer.

  • Container is removed (docker rm) — the writable layer is destroyed, but the volume and its data remain untouched on the host, owned by Docker, not by any specific container.

  • A new container can mount the same named volume (-v pgdata:/var/lib/postgresql/data) and immediately see the previous data — this is the mechanism behind zero-downtime container replacement for stateful services.

  • For bind mounts: docker run -v $(pwd)/src:/app/src myapp maps the exact host directory; edits made on the host (in your IDE) are instantly visible inside the running container, enabling live reload.

  • Databases (PostgreSQL, MySQL, MongoDB) always use named volumes for their data directory so the container can be recreated (image upgrade, config change) without losing data.

  • Local development: bind-mount your source code directory into the container so a Spring Boot DevTools or Vite/webpack dev server picks up file changes without rebuilding the image.

  • tmpfs for storing decrypted secrets or JWT signing material that an application needs at runtime but that must never be written to persistent disk, even accidentally.

  • Shared volumes between sidecar containers — e.g., an app container writes logs to a volume that a Filebeat/Fluentd sidecar container also mounts and tails, without either container needing direct access to the other's filesystem.

  • Always use named volumes (not anonymous ones) for anything you'd be upset to lose — name them explicitly so they show up clearly in docker volume ls and aren't accidentally pruned.

  • Prefer the explicit --mount syntax over the legacy -v shorthand in scripts/Compose files — it is more readable and fails loudly (rather than silently creating a directory) on typos.

  • Mark bind mounts read-only (readonly / :ro) whenever the container only needs to read host data (config files, certs) — limits blast radius if the container is compromised.

  • Use tmpfs for any data that should categorically never touch disk: short-lived decrypted secrets, temporary build scratch space, session data you're fine losing on restart.

  • Using a bind mount for a database's data directory in production — host path layout differences between environments (dev laptop vs prod VM vs Kubernetes node) make this fragile and non-portable.

  • Forgetting that anonymous volumes (-v /data with no source) accumulate silently on disk every time a container is recreated, since each new container gets a brand-new anonymous volume unless reused explicitly.

  • Assuming docker rm deletes associated named volumes — it does not, by default; volumes must be removed explicitly (or via docker rm -v, which only removes anonymous volumes, not named ones).

  • Mounting a host directory into a container running as a different UID than the host file owner, then being confused by Permission Denied errors — bind mounts respect the host's actual file ownership and permissions.

  • On Docker Desktop for Mac/Windows, bind-mounted source code can be slow due to the filesystem bridge between the VM and host OS; for I/O heavy workloads, consider named volumes or VirtioFS (now default on modern Docker Desktop) for better performance.

  • Use tmpfs for build caches or scratch directories that are write-heavy and don't need durability — RAM-backed I/O eliminates disk contention entirely.

  • Limit tmpfs size explicitly (tmpfs-size) to avoid an unbounded write workload silently consuming all available host memory and triggering OOM kills.

  • In production orchestrated environments (Kubernetes), the equivalent concepts are PersistentVolumes and PersistentVolumeClaims (durable, like named volumes with pluggable backends) and emptyDir (ephemeral, like a tmpfs or bind-mount-for-scratch-space pattern) — the Docker mental model transfers directly.

  • Back production named volumes with redundant, backed-up storage (cloud block storage with snapshots, or NFS with replication) rather than plain local disk on a single host.

  • Document and automate volume backup and restore procedures (e.g., a sidecar or cron job running pg_dump against the volume-backed data directory) — volumes are not a backup strategy by themselves.

  • Create a named volume, attach it to a Postgres container, insert data, remove and recreate the container with the same volume, and confirm data persists.

  • Run a container with an anonymous volume three times in a row and use docker volume ls to observe orphaned anonymous volumes accumulating.

  • Bind-mount a host directory read-only and attempt to write to it from inside the container to observe the permission failure.

  • Mount a tmpfs with a small size limit (e.g., 8m) and try writing more data than the limit to observe the resulting error.

  • Three storage types: named volumes (Docker-managed, portable), bind mounts (exact host path, direct), tmpfs (RAM-only, ephemeral).

  • Use named volumes for production persistent data; bind mounts for local dev live-reload or exposing specific host files; tmpfs for secrets/scratch space.

  • docker rm never deletes named volumes — they have an independent lifecycle.

  • Anonymous volumes silently accumulate; always name volumes explicitly in production.

  • Volumes map conceptually to Kubernetes PersistentVolumes; tmpfs/bind-for-scratch maps to emptyDir.

Want a visual for this concept?

Generate a diagram tailored to “Storage: Volumes, Bind Mounts & tmpfs” — the AI picks whichever visual (flowchart, comparison, sequence, etc.) best fits.

Sign in to generate a visual →

Practice quiz

Next Step

Continue to Docker Networking: Bridge, Host, Overlay, DNS & Port Mapping← Back to all Docker chapters