Both survive container removal. Both are described in almost identical syntax. This similarity is why the choice gets made carelessly, and why the consequences show up months later during a migration. The useful https://saborcitosrestaurant.com/ question is not “which one persists data” — they both do — but where the storage contract lives.
Two different contracts
With a named volume, the contract is between Docker and the container. Docker creates the storage, manages its location, and handles its lifecycle. The volume is abstracted away from the host’s directory layout entirely. You refer to it by name, and where it physically sits is Docker’s business.
With a bind mount, the contract is between the host filesystem and the container. A specific host directory is exposed inside the container at a specific path. It is a window onto the host filesystem, and Docker adds essentially nothing on top. Host permissions apply directly.
That single difference propagates outward into portability, backups, rebuilds, migrations, and permissions.
The heuristic that resolves most cases
If the data belongs to the application, start with a named volume. If the file belongs to the host workflow — you need to edit it in your editor, inspect it directly, or have another host process collect it — use a bind mount, deliberately.
Database storage belongs to the application. Nobody hand-edits database files. Named volume.
Source code you are actively editing, which the container should see change in real time, belongs to the host workflow. Bind mount.
A configuration file you want under version control alongside your compose file belongs to the host workflow. Bind mount.
Where each one hurts
Bind mounts tie a container to one host’s directory layout. Move the workload to another server and the path has to exist there too, with the right ownership. They also expose you directly to UID and GID mismatches, since files keep their host ownership and nothing reconciles the numbers between host and container.
Named volumes are a poor choice when you actually need host access to the files, because the volume is fully Docker-managed. Reaching into Docker’s storage directory to poke at volume contents by hand works, but it is a sign you probably wanted a bind mount.
There is also a platform wrinkle worth knowing: on Windows and macOS, Docker runs inside a VM, so bind mounts pass through an extra translation layer. This is slower and can mask permission problems that appear only once you deploy to a Linux host.
The default
Named volumes for application data; bind mounts when the host genuinely needs to own the file. Choosing deliberately at the start costs a minute. Choosing by accident costs an afternoon during your first migration.