By ProDevs
Published 2026-10-05
Last updated 2026-10-05
AI disclosure: drafted with AI assistance.
Disclosure: this page has no affiliate or referral links.
How we test: On 29 September 2026, date -u printed Tue Sep 29 20:09:16 UTC 2026. One Linux host already had Docker. Client and server were Engine 28.5.1, linux/amd64. docker info printed Server Version 28.5.1, Operating System Ubuntu 24.04.3 LTS, and Docker Root Dir /var/lib/docker. The image was alpine already on the host, with /bin/dd and /usr/bin/wc. No image pull. Each mount got one write. The log has a host wc -c for the bind file and none for the named volume. Containers and the volume were removed after the runs.
Who this is for: developers and DevOps engineers · Intermediate · You’ll need: Docker on a Linux host, and a directory the container must keep
Use a volume unless the host must see the files
Use a named volume when the container generates the files and Docker should own the directory. Use a bind mount when a process on the host has to read or edit that same path. Check the choice with docker inspect: Type is volume or bind.
Volumes are the preferred way to persist data that containers generate and use. Docker stores a volume in a directory on the host, mounts that directory into the container, and isolates it from the rest of the host. A bind mount takes a file or directory that already lives on the host and mounts it into the container. Bind mounts follow the host’s directory layout and operating system. (Docker docs: volumes)
On this host both mounts kept a 16777216-byte file. The named-volume dd exited 0 and printed 16777216 bytes (16.0MB) copied, 0.057925 seconds, 276.2MB/s. The bind-mount dd exited 0 and printed 16777216 bytes (16.0MB) copied, 0.041953 seconds, 381.4MB/s. Inside each container, wc printed 16777216 /data/blob. Host wc -c of the bind file also printed 16777216. Read those two speeds as one sample each. Pick the mount by who must open the directory, then time your own workload if the rate matters.
The machine under Docker is a separate choice. Docker or a VPS is that split.
Who it’s for
You are about to persist files from a container: a database directory, an upload folder, or a build cache. You use docker run or Compose. You want the inspect line that tells you which mount you actually have, and a write you can repeat.
A storage-driver tune-up and a Kubernetes volume are other jobs. VPS for AI coding agents is the RAM floor when the long-running process is an agent.
Cloudflare vs a VPS is the neighboring article when you are choosing which bill stays up between requests.
Not for
Storage-driver tuning and Kubernetes volumes are separate jobs. This guide covers named volumes and bind mounts with docker run and Compose on one Linux host.
What inspect is telling you
When you create a volume, Docker keeps it in its storage directory on the host. Mounting the volume into a container mounts that directory. That is similar to a bind mount, except Docker manages the volume. (Docker docs: volumes)
A volume’s contents outlive the container. Destroying the container destroys its writable layer. It does not remove the volume. When no container is using a volume, Docker still has it, and it is not deleted on its own. Removing a volume is its own step. A volume also does not increase the size of the containers that use it.
Using a volume is faster than writing into the container’s writable layer, because that layer goes through a storage driver. The driver builds a union filesystem, and that extra step is slower than writing straight to the host filesystem. That comparison is volume versus the writable layer.
The volumes page lists easier backup and migration, the Docker CLI, sharing between containers, pre-populating a volume, and “when your application requires high-performance I/O” as reasons to use a volume. The high-performance line is a use case on that page. Volumes are a poor fit when you need to open the files from the host, because Docker manages the directory completely. Use a bind mount when the container and the host both need the files. (Docker docs: volumes)
A bind mount has write access to the host path by default, so the container can change those files. --mount does not create a missing bind source. It errors, and the sample text is bind source path does not exist. The bind-mount inspect example uses "Type": "bind". (Docker docs: bind mounts)
The volumes documentation example shows "Type": "volume" and a source under /var/lib/docker/volumes/.../_data. The docker volume inspect example Mountpoint is /var/lib/docker/volumes/my-vol/_data. Those paths are the examples on the documentation page.
| Question | Named volume | Bind mount |
|---|---|---|
| Who creates the directory | Docker, inside its storage directory | You, on the host, before --mount type=bind |
Inspect Type |
volume |
bind |
| Host editor needs the files | Awkward. Docker owns the directory | The host path is the directory |
After docker rm |
Data stays until you remove the volume | Data stays in the host directory you mounted |
| Writable layer | A volume is the faster place to write, compared with that layer | A bind mount also skips the writable layer for that path |
Copy-paste: docker run
Sixteen records totaling 16777216 bytes is 16 × 1048576. That is the write both runs printed: 16+0 records in, 16+0 records out, then 16777216 bytes.
Named volume. Create it, write, then count the file from a second container so you are not reading the writable layer.
docker volume create app-data
docker run --rm \
--mount type=volume,source=app-data,target=/data \
alpine \
dd if=/dev/zero of=/data/blob bs=1048576 count=16
docker run --rm \
--mount type=volume,source=app-data,target=/data \
alpine \
wc -c /data/blob
Drop --rm on the container you want to inspect, then read mounts:
docker inspect CONTAINER --format '{{range .Mounts}}type={{.Type}} name={{.Name}} dest={{.Destination}}{{println}}{{end}}'
On the lab volume, that kind of line printed type volume and destination /data.
Bind mount. Create the host directory first. --mount type=bind fails when the source is missing.
mkdir -p ./host-data
docker run --rm \
--mount type=bind,source="$(pwd)/host-data",target=/data \
alpine \
dd if=/dev/zero of=/data/blob bs=1048576 count=16
wc -c ./host-data/blob
On the lab bind mount, inspect printed type bind and destination /data, and the Name field was empty. Host wc -c of that file printed 16777216, the same count wc printed inside the container.
Remove a named volume only when you mean to delete the files. docker rm leaves the volume. docker volume rm app-data is the separate step. For the bind mount, deleting ./host-data deletes the files, because that directory is the data.
Copy-paste: Compose
Compose uses the same two mounts. A named volume is a key under the top-level volumes map. A bind mount is a host path on the left of the short syntax. Long syntax sets type to volume or bind, which is the same field docker inspect prints. (Compose services)
services:
app:
image: alpine
command: ["dd", "if=/dev/zero", "of=/data/blob", "bs=1048576", "count=16"]
volumes:
- type: volume
source: app-data
target: /data
volumes:
app-data:
services:
app:
image: alpine
command: ["dd", "if=/dev/zero", "of=/data/blob", "bs=1048576", "count=16"]
volumes:
- type: bind
source: ./host-data
target: /data
Create ./host-data before you start the bind file. The lab itself was docker run, so treat the YAML as the same two mounts written for Compose. The dd arguments are the record size and count that match the printed 16+0 lines and 16777216 bytes.
Symptom, cause, fix
| What you see | What it usually means | What to change |
|---|---|---|
Type is volume and the host editor cannot find the files |
Docker owns the directory | Switch that path to a bind mount if a host process must read it, or use docker cp / a volume backup when Docker should keep owning it |
Type is bind and the container changed files you care about on the host |
Bind mounts are writable on the host path by default | Point the mount at a directory you can afford to change, or mount it read-only |
Start fails with bind source path does not exist |
--mount type=bind will not create the host directory |
mkdir the source, then start again |
Files vanished after docker rm and inspect never showed a mount on /data |
The writes were in the writable layer, which dies with the container | Add a volume or a bind mount and write there |
The container is gone and docker volume ls still shows the name |
Removing the container does not remove the volume | docker volume rm only when you want the bytes gone |
Both dd runs exited 0 and you want to know which is “faster” |
You have one sample on each mount | Keep the mount that matches who must see the files. Time your real job before you switch for speed |
wc inside the container and wc -c on the host disagree |
You are counting different paths, or the bind source is not the directory you think | Inspect Type and the destination. For a bind mount, count the host directory you passed as the source |
Mistakes that waste a day
Writing into the container and calling it persistence. The writable layer is destroyed with the container. A volume or a bind mount is what keeps the file. Our wc lines were on /data/blob after a mount to /data.
Picking a volume because the docs mention high-performance I/O. That phrase is a use case. The sentence about speed on the same page compares a volume with the writable layer. Our two dd lines are one write of 16777216 bytes each: 0.057925 seconds at 276.2MB/s on the volume, 0.041953 seconds at 381.4MB/s on the bind mount.
Expecting the host to open a named volume like a project folder. Docker manages that directory. If a person or a cron job on the host must read the files, use a bind mount. The lab’s host wc -c was on the bind file, and it matched the container count.
Using -v habits with a missing directory and expecting --mount to mkdir. --mount type=bind errors when the source does not exist. Create the directory first.
Deleting the container and assuming the database is gone, or assuming it is safe. A named volume is still there until docker volume rm. A bind mount is still there until you delete the host directory.
Alternatives and limitations
The container’s writable layer. Fine for scratch files, but it is destroyed with the container, so it is not persistence.
Drawbacks of a named volume. Docker manages its directory, so a person or a cron job on the host cannot treat it like a project folder.
Drawbacks of a bind mount. It depends on a host path that must already exist (--mount type=bind errors when it does not), and it ties the container to that host’s directory layout.
What our test does not cover. The speed figures are one 16 MB write each on one host. Choose the mount by who needs to see the files, not by those two rates.
What we measured
One host, Engine 28.5.1, Ubuntu 24.04.3 LTS, Docker root /var/lib/docker, image alpine already local. One write on a fresh named volume, then the same write on a fresh bind mount. Both destinations were /data. The volume inspect line was type volume. The bind inspect line was type bind with an empty Name.
| Named volume | Bind mount | |
|---|---|---|
dd exit |
0 | 0 |
| Records | 16+0 in, 16+0 out |
16+0 in, 16+0 out |
Bytes dd printed |
16777216 (16.0MB) |
16777216 (16.0MB) |
Time and rate dd printed |
0.057925 seconds, 276.2MB/s |
0.041953 seconds, 381.4MB/s |
wc inside the container |
16777216 /data/blob |
16777216 /data/blob |
Host wc -c |
not in the log | 16777216 |
16 × 1048576 = 16777216, which is the byte count both dd lines and both container wc lines printed, and the byte count host wc -c printed for the bind file.
Takeaway: Both mounts kept the file the container wrote. The bind mount was also visible to wc on the host, at the same byte count. The volume was the mount you choose when Docker should own the directory. The bind mount was the mount you choose when the host must see it. The two rates are this pair of writes on this host at Tue Sep 29 20:09:16 UTC 2026.
FAQ
Should I use a volume or a bind mount?
Use a named volume for data the container generates and Docker should manage. Use a bind mount when the host and the container both need the files. Confirm with docker inspect and read Type.
Will the files survive docker rm?
A volume survives until you remove the volume. A bind mount survives in the host directory you mounted. The container’s own writable layer does not survive.
Why can I not find the volume files on the host?
Docker manages that directory and isolates it from the rest of the host. The documentation example mountpoint is under /var/lib/docker/volumes/.../_data. If you need a normal project path, use a bind mount.
The container will not start and the error says the bind source does not exist. What now?
Create the host directory, then start again. --mount type=bind does not create a missing source.
Is a volume faster than a bind mount?
Docker says a volume is faster than the container writable layer. Our lab did not time that layer. It timed one 16777216-byte write on each mount: 276.2MB/s on the volume and 381.4MB/s on the bind mount. Use that as a sample from this host, and time your own job before you switch mounts for speed.
Can a bind mount change files I did not mean to expose?
Yes. Bind mounts can write to the host path by default. Mount a directory you mean to share.
What did the 29 September write show?
Engine 28.5.1 on Ubuntu 24.04.3 LTS. Both dd runs exited 0 and printed 16777216 bytes. Container wc printed 16777216 /data/blob for each. Host wc -c of the bind file printed 16777216. Volume inspect was type volume at /data. Bind inspect was type bind at /data with an empty name.
If the files are on the wrong mount
This guide uses a named volume when Docker should own the files, and a bind mount when the host must see them. If the data is on the other mount, write the path you inspected.
Use the contact form. We reply in writing, usually within one business day. The reply says we can help, we should not take this on, or we need one detail. That look is free. If we are full, we say so. Do not send passwords or keys.
If that reply says a paid written audit is the next step, the range is ₹15,000–₹25,000. That is the range on the services page. This article has no payment link.
Sources
- Volumes: docs.docker.com/engine/storage/volumes
- Bind mounts: docs.docker.com/engine/storage/bind-mounts
- Compose service
volumes: docs.docker.com/reference/compose-file/services


