Skip to content

Volumes vs Bind Mounts

PropertyNamed VolumeBind Mount
Path managed byDockerYou
Host path requiredNoYes
PortabilityHigh — works on any hostLow — path must exist on every host
PerformanceOptimised by Docker storage driverDirect host filesystem (fast on Linux, slower on macOS/Windows)
Backupdocker volume inspect + tar containerCopy files directly from the host path
Typical use caseDatabase files, app state, uploadsSource code, config files in development
Works in productionYesRarely (depends on host layout)
  • You need data to survive container replacements (databases, object storage, cache).
  • You are deploying to a remote host or CI/CD environment where the host path may differ.
  • You want Docker to own the lifecycle of the storage.
  • You are developing locally and want live code reload without rebuilding the image.
  • You need to inject a config file from the host into the container at runtime.
  • You are running tools (linters, compilers) that produce output you want directly on the host.

Both volume types support read-only mounts. The container can read data but cannot write to the mount target.

Named volume, read-only:

Terminal window
docker run --rm -v mydata:/app/data:ro alpine ls /app/data

Bind mount, read-only:

Terminal window
docker run --rm -v $(pwd)/config:/etc/app/config:ro myimage

With --mount syntax (both types):

Terminal window
# Volume
docker run --rm --mount type=volume,source=mydata,target=/app/data,readonly myimage
# Bind
docker run --rm --mount type=bind,source=$(pwd)/config,target=/etc/app/config,readonly myimage

Read-only mounts are a security best practice when the container only needs to read the data — they prevent a compromised or buggy process from overwriting important files.

The snippet below demonstrates both mount types side by side so you can observe the difference in a single session.

# --- Named volume ---
docker volume create compare-vol

# Write via container
docker run --rm -v compare-vol:/data alpine sh -c "echo 'from named volume' > /data/note.txt"

# Read from a new container (data persists)
docker run --rm -v compare-vol:/data alpine cat /data/note.txt

# --- Bind mount ---
mkdir -p /tmp/compare-bind
echo 'from bind mount' > /tmp/compare-bind/note.txt

# Read from container via bind mount
docker run --rm -v /tmp/compare-bind:/data alpine cat /data/note.txt

# --- Read-only mount ---
docker run --rm -v /tmp/compare-bind:/data:ro alpine sh -c "cat /data/note.txt && echo 'trying to write...' && echo 'blocked' > /data/note.txt || echo 'Write blocked as expected'"

# Clean up
docker volume rm compare-vol
rm -rf /tmp/compare-bind
Which storage option has higher portability across different host machines?
What is the correct `:ro` flag position for a read-only bind mount using `-v` syntax?
Why might bind mounts perform slower on macOS and Windows compared to Linux?
A read-only mount is a security best practice because it prevents what?