Docker Volume vs Bind Mount: Which One to Use and Why

Use a volume for data the container owns, such as a database, and a bind mount when you need to see or edit the files from the host, such as source code during development. A volume is storage that Docker creates and manages; a bind mount maps an existing folder on your computer straight into the container.

docker run -d -v pgdata:/var/lib/postgresql/data postgres   # volume (a name)
docker run -d -v "$(pwd)"/src:/app/src node:22           # bind mount (a path)

The -v syntax is the same for both. A plain name on the left creates or reuses a volume; anything that looks like a path (starting with /, ./ or a drive letter) is a bind mount.

Why you need either one

Files a container writes to its own filesystem go into its writable layer, and Docker's storage overview is explicit: "Data written to the container layer doesn't persist when the container is destroyed." Upgrading an image means removing the old container and creating a new one, so anything you want to survive that has to live in a mount.

Docker volume vs bind mount compared

VolumeBind mount
Who manages itDocker (docker volume ls, rm, prune)You; it is an ordinary host folder
Where it livesDocker's storage area, e.g. /var/lib/docker/volumes/ on LinuxAny path you choose
Depends on host folder layoutNoYes, the path must exist on that machine
Mounting over a folder that already has filesEmpty volume is filled with the image's filesImage's files are hidden by the host folder
Easy to edit from the hostNoYes
Back up and migrateDocker documents a tar procedureCopy the folder
Container can change host filesOnly inside the volumeYes, read-write by default

Docker's own guidance follows the same split. The volumes page recommends volumes for persisting container data and says they are "easier to back up or migrate than bind mounts", and the bind mounts page lists sharing source code, build output and host config files as the use cases for bind mounts.

The difference that bites: existing files at the mount point

Mount something at a path where the image already has files, and the two types behave in opposite ways:

  • Empty volume: Docker copies the image's existing files at that path into the volume. That is why -v pgdata:/var/lib/postgresql/data works on first start. Add the volume-nocopy option to --mount if you don't want the copy.
  • Bind mount: the host folder covers the path, and the image's files there become invisible. Bind-mount an empty host folder over /app and the container sees an empty /app, even though the image has your built app in it.

The second case is behind a lot of "it works without the mount" reports, typically a Node project where a bind mount of the project folder hides the node_modules that the image installed. A common fix is a second mount, a volume, on just that subfolder, so it isn't covered by the host folder.

-v or --mount?

Both flags create either type. --mount spells out each field and Docker's documentation says it is preferred:

docker run -d --mount type=volume,source=pgdata,target=/var/lib/postgresql/data postgres
docker run -d --mount type=bind,source="$(pwd)"/target,target=/app nginx

The practical difference shows up when a bind-mount source path doesn't exist. -v silently creates it as an empty directory, which then hides the container's files. --mount refuses with an error like this one from Docker's docs:

docker: Error response from daemon: invalid mount config for type "bind": bind source path does not exist: /dev/noexist.

A typo in a path gives you a loud error with --mount and a mysteriously empty folder with -v.

When to use a volume

  • Databases and any app state: PostgreSQL, MySQL, Redis persistence, uploaded files.
  • Data shared by several containers, mounted by name in each.
  • Anything you will move to another machine, since the container doesn't depend on a particular host path.

Manage them with docker volume create, ls, inspect, rm and prune. To back one up, Docker's docs mount the volume into a throwaway container together with a host folder and tar it:

docker run --rm --volumes-from dbstore -v "$(pwd)":/backup ubuntu tar cvf /backup/backup.tar /dbdata

Here dbstore is the container using the volume and /dbdata is where the volume is mounted in it.

When to use a bind mount

  • Source code in development, so your editor's changes show up in the container straight away and a dev server can reload.
  • Config files you maintain on the host, such as an nginx.conf. Mount them read-only.
  • Output you want on the host, such as build artifacts or test reports.

Make bind mounts read-only whenever the container only needs to read: :ro with -v, ,readonly with --mount.

docker run -d -p 8080:80 -v "$(pwd)"/nginx.conf:/etc/nginx/nginx.conf:ro nginx

Docker's bind mount page warns that a container with read-write access can create, change or delete host files, including system files if you mount a system folder. Never bind-mount / or your home folder into a container you don't fully trust.

Docker Desktop on Windows: keep bind-mounted code in WSL

With Docker Desktop on the WSL 2 backend, where the files sit matters. Docker's WSL best-practice page says performance is much higher when files are bind-mounted from the Linux filesystem, and discourages mounting Windows paths such as /mnt/c/users. File-watching dev servers also depend on it: the same page says Linux containers only receive file change events when the files live in the Linux filesystem. Keep the project in your WSL home folder (for example ~/my-project) and bind-mount it from there. Volumes are unaffected, since they already live inside Docker's Linux environment.

What about tmpfs?

A third type, --mount type=tmpfs,target=/tmp/cache, keeps files in the host's memory and never writes them to disk. Use it for scratch data or secrets you don't want written anywhere, and expect it to be empty every time the container starts. For the networking side of the same containers, see Docker port mapping for exposing the app, and Docker vs virtual machine for why container filesystems are disposable in the first place.

Frequently asked questions

Is a Docker volume faster than a bind mount?
On a Linux host they perform alike: Docker's storage overview says volumes give the same raw file performance as the host filesystem. The difference shows up with Docker Desktop on Windows, where Docker's WSL guidance says bind mounts from the Linux filesystem are much faster than bind mounts of Windows paths such as /mnt/c.
Does docker rm delete my volume?
No, not a named volume. Removing a container leaves named volumes in place until you run docker volume rm or docker volume prune. Anonymous volumes are different: starting a container with --rm deletes its anonymous volumes when the container is removed.
Where are Docker volumes stored on disk?
Docker keeps each volume in a directory it manages. On a Linux host docker volume inspect shows a Mountpoint under /var/lib/docker/volumes/. With Docker Desktop on Windows or macOS that path is inside Docker's Linux virtual machine, so you can't browse it like a normal folder; use docker cp or a helper container instead.
Can two containers share the same volume?
Yes. Mount the same named volume in both, for example -v shared:/data in each docker run. Docker's volumes documentation lists safe sharing between containers as one of the reasons to use a volume. The applications still have to coordinate their own writes, as with any shared folder.

Sources