Volume Mount
A configuration that connects a directory or file from outside a container into the container's filesystem, making data accessible to the container process. Docker supports three mount types: named volumes, bind mounts, and tmpfs.
Volume Mount — Connecting Storage to Docker Containers
What Is a Volume Mount in Simple Terms?
By default, everything a Docker container writes to disk disappears when the container is removed. A volume mount solves this — it connects a storage location from outside the container into the container's filesystem, so data persists beyond the container's lifetime.
Think of it like plugging an external hard drive into a laptop. The files on the drive are accessible while the drive is plugged in. When you unplug it (stop the container), the files are still on the drive. Plug it into a different laptop (new container), the same files are there.
+------------------------------------------+| Docker Container || || /app/ <- container filesystem || /tmp/ <- container filesystem || /var/lib/postgresql/data <- MOUNTED || | |+----------------|-------------------------+ | | volume mount |+----------------|-------------------------+| Host | || /var/lib/docker/volumes/pgdata/_data || (named volume managed by Docker) |+------------------------------------------+Three Mount Types
+------------------------------------------+| Named Volume || -v postgres-data:/var/lib/postgresql/data|| || Managed by Docker || Stored at /var/lib/docker/volumes/ || Survives container removal || Best for: production data (databases) |+------------------------------------------+ +------------------------------------------+| Bind Mount || -v /host/path:/container/path || || Host path mapped directly || Changes on host appear in container || Changes in container appear on host || Best for: dev hot-reload, config files |+------------------------------------------+ +------------------------------------------+| tmpfs Mount || --tmpfs /tmp || || In-memory only (RAM) || Never written to disk || Lost when container stops || Best for: sensitive temp files, caches |+------------------------------------------+Named Volumes — Production Persistent Storage
# Create a named volumedocker volume create postgres-data # Mount it when running a containerdocker run -d \ --name postgres \ -v postgres-data:/var/lib/postgresql/data \ -e POSTGRES_PASSWORD=secret \ postgres:15 # Data persists — remove and recreate container, data is still theredocker rm -f postgresdocker run -d \ --name postgres-new \ -v postgres-data:/var/lib/postgresql/data \ -e POSTGRES_PASSWORD=secret \ postgres:15# All your tables and data are still there # List volumesdocker volume ls# DRIVER VOLUME NAME# local postgres-data # Inspect a volumedocker volume inspect postgres-data# Shows mountpoint: /var/lib/docker/volumes/postgres-data/_data # Remove a volume (permanent data deletion)docker volume rm postgres-dataBind Mounts — Development Hot Reloading
# Mount current directory into containerdocker run -d \ --name dev-api \ -p 3000:3000 \ -v $(pwd)/src:/app/src \ node:20-alpine \ node /app/src/server.js# Edit src/server.js on your host# Container sees changes immediately — no rebuild needed # Mount a config file (read-only)docker run -d \ --name nginx \ -v $(pwd)/nginx.conf:/etc/nginx/nginx.conf:ro \ nginx:1.25# :ro = read-only, container cannot modify the host file # Inspect mounts on a running containerdocker inspect postgres \ --format '{{range .Mounts}}{{.Type}} {{.Source}} -> {{.Destination}}{{println}}{{end}}'# volume /var/lib/docker/volumes/pgdata/_data -> /var/lib/postgresql/dataVolume Mounts in Docker Compose
version: "3.8" services: api: image: payment-api:latest volumes: # Named volume - payment-data:/app/data # Bind mount for dev hot-reload - ./src:/app/src # Config file injection (read-only) - ./config/prod.json:/app/config/prod.json:ro # tmpfs for temp files - type: tmpfs target: /tmp postgres: image: postgres:15 volumes: - postgres-data:/var/lib/postgresql/data volumes: postgres-data: # declared at top level — Docker manages it payment-data:Backup and Restore
# Backup a named volume to a tar filedocker run --rm \ -v postgres-data:/source:ro \ -v $(pwd):/backup \ alpine \ tar czf /backup/postgres-backup.tar.gz -C /source . # Restore from backupdocker volume create postgres-data-restoreddocker run --rm \ -v postgres-data-restored:/target \ -v $(pwd):/backup:ro \ alpine \ tar xzf /backup/postgres-backup.tar.gz -C /targetWhen to Use Each Mount Type
| Use Case | Mount Type | Why |
|---|---|---|
| PostgreSQL data | Named volume | Persists, Docker-managed, easy backup |
| Redis persistence | Named volume | Survives restarts |
| Dev code hot-reload | Bind mount | Host edits appear instantly in container |
| Config file injection | Bind mount (:ro) |
Use host file without rebuilding image |
| Sensitive temp files | tmpfs | Never written to disk |
| High-speed scratch space | tmpfs | Fastest I/O, no persistence needed |
TipUse the
--mountflag syntax instead of-vfor clarity in scripts —--mount type=volume,source=pgdata,target=/var/lib/postgresql/data. It is more verbose but each option is named, making it impossible to mix up source and target.
Remember
docker compose downkeeps volumes safe.docker compose down -vdeletes all volumes and all data permanently. Never rundown -von a production system unless you intend to destroy all data.
Common MistakeUsing bind mounts in production with a host path that might not exist on every server. Bind mounts require the exact host path to exist and have correct permissions. Named volumes are created automatically by Docker if they do not exist. Use named volumes in production, bind mounts in development only.
SecurityBe careful when bind-mounting host directories into containers. A container with a bind mount to a sensitive directory (like
/etcor/root) can read host system files. Always use:ro(read-only) for config files and never bind-mount directories that contain credentials or SSH keys into production containers.
Frequently Asked Questions
What's the practical difference between a named volume and a bind mount that determines which one to use?
A bind mount points at a specific path on the host filesystem (e.g. `-v /home/user/code:/app`), so its content and permissions are entirely host-dependent — useful for local development where you want live code editing reflected inside the container. A named volume (`-v mydata:/var/lib/data`) is managed entirely by Docker in its own storage area, portable across hosts, and the right choice for persistent application data like database files that shouldn't depend on host directory structure.
What's a common production mistake involving volume mounts?
Bind-mounting source code into a container in a way that was only meant for local dev, then carrying that same docker-compose file into production — this can silently mask the image's actual baked-in code with whatever happens to be on the production host's filesystem, defeating the point of immutable images. Also watch file permission mismatches: a container process running as a non-root UID often can't write to a bind-mounted host directory owned by a different UID, causing confusing permission-denied errors only in certain environments.