| Tested on | Red Hat Enterprise Linux 10.2 (Coughlan) |
|---|---|
| Package | podman-5.8.2-5.el10_2.x86_64 |
| Applies to | Any Linux host with Podman installed |
| Privilege | Rootful examples on the lab host; same commands work rootless |
| Scope | Choosing between Podman-managed named volumes and host-directory bind mounts — persistence, host access, portability, initial copy-up behavior, backup paths, SELinux relabel flags at a high level, rootless ownership trade-offs, and -v vs --mount terminology. Does not cover full volume command tutorials, AVC diagnosis, user-namespace mapping depth, or storage.conf paths. |
| Related guides | Run containers with podman run Install Podman on RHEL |
Podman can attach persistent storage two ways: a Podman-managed named volume, or an existing host directory as a bind mount. Both survive container removal. The choice is who owns the path, how you back up data, and how SELinux and rootless UID mapping interact with that path — not whether data persists at all.
Podman bind mount vs volume: quick answer
Use a Podman named volume when:
- the container owns the application data
- the exact host path does not matter
- you want
podman volume inspect,export, andimport - run commands should not hard-code
/home/alice/...on every host
Use a bind mount when:
- the host and container must share a known directory
- configuration or source files already live on the host
- host editors, backup agents, or other services need direct filesystem access
- the workload depends on a specific path such as
/etc/ssl/certs
| Characteristic | Named volume | Bind mount |
|---|---|---|
| Source | Podman-managed volume | Existing host path |
| Host path chosen by user | No | Yes |
| Podman lifecycle management | Yes | No |
| Easy host access | Less direct | Direct |
| Persistent | Yes | Yes |
| Portable CLI/config | Generally better | Depends on host path |
| Podman volume export/import | Yes | No — use normal filesystem backup tools |
| SELinux on enforcing hosts | Usually simpler | Host labels often need :z or :Z |
| Rootless ownership | Podman can initialize volume ownership | Host UID mapping often needs explicit handling |
Neither option is universally better. Match the mount type to how the data is produced and consumed.
What is a Podman named volume?
A named volume is storage Podman allocates and tracks by name. Create and mount it like this:
podman volume create podman-volume-demoWrite through a container mount to prove the volume accepts data:
podman run --rm -v podman-volume-demo:/data docker.io/library/alpine:3.20 sh -c 'echo "volume data" > /data/volume.txt'Podman picks the host location — you reference podman-volume-demo in run commands. The volume outlives any one container, mounts into another container by name, and supports podman volume inspect, export, and import. Command-level detail lives in Podman volumes.
What is a bind mount?
A bind mount attaches a host directory the container sees at a container path. Prepare data on the host first:
mkdir -p ~/podman-bind-demoSeed a file the container will read:
echo 'bind-mount-content' > ~/podman-bind-demo/example.txtOn SELinux-enforcing RHEL hosts, an unlabeled home directory may deny container reads until you relabel the mount — the lab saw Permission denied without a relabel option:
podman run --rm -v ~/podman-bind-demo:/data docker.io/library/alpine:3.20 cat /data/example.txtSample output without relabel:
cat: can't open '/data/example.txt': Permission deniedAdd a private relabel for a dedicated project directory:
podman run --rm -v ~/podman-bind-demo:/data:Z docker.io/library/alpine:3.20 cat /data/example.txtSample output:
bind-mount-contentThe syntax tells you the mount type:
podman-volume-demo:/data → named volume (no slashes in source name)
~/podman-bind-demo:/data → bind mount (host path as source)Container writes land in the host directory immediately — verify from the host:
podman run --rm -v ~/podman-bind-demo:/data:Z docker.io/library/alpine:3.20 sh -c 'echo container-write >> /data/example.txt'The append should appear in the host file immediately:
cat ~/podman-bind-demo/example.txtSample output:
bind-mount-content
container-writePodman does not create or delete the host directory when you remove the container.
Compare persistence
Both mount types keep data after the container exits.
Named volume data remains in Podman storage:
podman volume mount podman-volume-demoSample output:
/var/lib/containers/storage/volumes/podman-volume-demo/_dataBind-mounted data remains at the host path you chose:
ls -la ~/podman-bind-demo/The claim that "only volumes are persistent" is wrong. Bind mounts are persistent too. The distinction is who manages and addresses the storage — Podman volume name versus host directory path.
Compare host access
Bind mount
You pick the path — for example ~/podman-bind-demo or /srv/application-data. Host tools edit files in place without podman volume mount.
Named volume
You address storage by volume name in run commands. When you need the host path, ask Podman:
podman volume inspect --format '{{.Mountpoint}}' podman-volume-demoOr mount the volume on the host for maintenance:
podman volume mount podman-volume-demoNamed volumes are not hidden from the host — they are Podman-managed rather than tied to an application-chosen directory in your home tree.
Compare portability
This command does not depend on /home/alice/project/data existing on every machine:
podman run -v application-data:/var/lib/app IMAGEAny host with a volume named application-data (or auto-created on first run) can use the same line. Unlike an absent named volume, which Podman creates automatically by default, a bind-mount source path must already exist.
Bind mounts depend on the host path, ownership, filesystem, SELinux labels, and whether files already exist. "Portable" here means configuration independence — not that volume data teleports between hosts. You still migrate named-volume data with podman volume export or your backup tooling when you change machines.
Compare initial data behavior
By default, when a newly created named volume is first initialized at a non-empty container path, Podman copies the existing image content at that destination into the volume. This happens only during initial initialization; later mounts do not repeat the copy. Use nocopy when you want the new volume to remain empty. Bind mounts overlay the host directory and hide whatever was in the image at that path.
Build an image with a default file under /app:
podman build -t localhost/bind-vs-demo:v1 -f - . <<'EOF'
FROM docker.io/library/alpine:3.20
RUN mkdir -p /app && echo default-config > /app/default.conf
EOFMount a new named volume at /app:
podman volume create podman-copyup-demoFirst container use should surface the image default through copy-up:
podman run --rm -v podman-copyup-demo:/app localhost/bind-vs-demo:v1 cat /app/default.confSample output:
default-configPodman copied image content into the volume on first use.
Bind an empty host directory at the same path:
mkdir -p ~/podman-bind-emptyList /app inside the container — an empty host directory hides image files:
podman run --rm -v ~/podman-bind-empty:/app:Z localhost/bind-vs-demo:v1 ls -la /appSample output:
total 0
drwxr-xr-x 2 root root 6 Aug 22 17:25 .
dr-xr-xr-x 1 root root 28 Aug 22 17:25 ..The image still contains default.conf, but the mount hides it:
podman run --rm -v ~/podman-bind-empty:/app:Z localhost/bind-vs-demo:v1 cat /app/default.confSample output:
cat: can't open '/app/default.conf': No such file or directoryCopy-up helps seed databases and default configs into new volumes. Bind mounts are right when you intentionally replace the image path with host content.
Compare backup and restore
Named volumes use Podman-native tools — podman volume export and podman volume import (see Podman volumes for the full procedure).
Bind-mounted data is already a normal host directory. Back it up with your filesystem tools — tar, rsync, or your backup agent — at the path you mounted.
That split is a practical decision factor: Podman-managed blobs versus directories you already manage on the host.
SELinux: bind mount vs volume
On SELinux-enforcing systems, bind-mounted host directories keep their existing security contexts. Container processes may be denied until you relabel the mount:
podman run --rm -v ~/podman-bind-demo:/data:Z docker.io/library/alpine:3.20 cat /data/example.txtBrief flag meanings:
:z— shared relabel; multiple containers may use the volume:Z— private relabel; this container's use only
Named Podman volumes usually avoid relabeling a random directory under $HOME because Podman places them for container workloads. Named volumes can still hit UID and permission issues — they are not immune.
:z or :Z to broad system trees such as /home, /var, or /etc. Relabeling system content can break other confined services. Restrict relabel flags to dedicated data directories you own.
AVC logs, ausearch, and the full diagnostic tree belong in Fix Podman volume permission denied — not on this comparison page.
Rootless Podman: bind mount vs volume
Rootless Podman runs containers in user namespaces. UID 1000 inside a container may map to a different host UID depending on namespace settings.
Named volumes are often easier because for a newly initialized local named volume, Podman can adjust the volume mount-point ownership to the container user. This does not apply universally to already-used volumes or external volume drivers.
Bind mounts point at directories that already belong to host users. A container process may not see the ownership you expect without extra flags or host-side changes — --userns=keep-id, :U, podman unshare chown, or idmapped mounts where supported.
Do not assume named volumes erase every rootless permission problem. They reduce host-path surprises; they do not replace understanding UID mapping. See Fix Podman volume permission denied and Podman user namespaces when mounts fail with permission errors.
Understand the risk of :U
The :U mount option recursively changes ownership of the host source to match the container user's mapped host UID/GID:
-v /host/path:/container/path:UThat can be wrong for directories host applications also use directly. Do not add :U to every rootless bind mount by default — test on a disposable directory first. Detailed scenarios live in the permissions guide.
Read-only bind mount vs volume
Both mount types accept :ro:
podman run --rm -v podman-volume-demo:/data:ro docker.io/library/alpine:3.20 cat /data/volume.txtThe same read-only flag works on a bind-mounted config directory:
podman run --rm -v ~/podman-bind-demo:/data:ro,Z docker.io/library/alpine:3.20 cat /data/example.txtA common pattern: read-only bind mount for configuration the host maintains, writable named volume for application state the container owns. That is a starting point, not a rule for every workload.
Bind mount vs volume examples
| Workload | Recommended starting point | Why |
|---|---|---|
| Database data | Named volume | Podman-managed persistent state |
| Application upload directory | Named volume | Container-owned files |
| Web source during development | Bind mount | Host editor, immediate sync |
| Configuration file | Read-only bind mount | Host manages config |
| TLS certificates on host | Read-only bind mount | Path already host-managed |
| Disposable cache | Volume or tmpfs | Depends on persistence needs |
| Host log directory consumed elsewhere | Bind mount | Host path must be exact |
Adjust when your security, backup, or multi-tenant requirements differ.
-v and --mount work for both
-v does not mean "volume only" and --mount does not mean "bind only." Both syntaxes express either mount type — the source and type= field decide.
Named volume with --mount:
podman run --rm --mount type=volume,src=podman-volume-demo,dst=/data docker.io/library/alpine:3.20 cat /data/volume.txtBind mount with --mount (relabel when SELinux blocks access):
podman run --rm --mount type=bind,src=$HOME/podman-bind-demo,dst=/data,relabel=private docker.io/library/alpine:3.20 cat /data/example.txt-v versus --mount style is covered in Podman volumes. Here the point is mount type, not which flag you type first.
Which should you choose?
Does the container need a specific existing host path?
│
├── Yes → Bind mount
│
└── No
│
├── Persistent app data → Named volume
│
└── Temporary data → consider tmpfs or container layerA second check:
Does the host need to edit/read files at a stable path?
│
├── Yes → Bind mount is usually simpler
└── No → Named volume is usually simplerWhen in doubt, start with a named volume for application state you do not need to browse from the host daily, and bind-mount only the paths that must stay visible to host tooling.
References
- podman-run man page —
-vand--mount - podman-volume man page
- Podman rootless documentation
Summary
Podman bind mounts and named volumes are both persistent. Bind mounts expose a host directory you choose; named volumes expose a Podman-managed name and leave path selection to Podman. On the lab host, bind mounts under $HOME needed :Z on SELinux-enforcing RHEL while named volumes worked without relabeling that home path.
Copy-up seeds a new named volume from image content during initial volume initialization only; use nocopy to keep a new volume empty. An empty bind mount hides image files at the mount point without deleting them from the image layer. Back up named volumes with podman volume export; back up bind mounts with normal filesystem backup tools.
Rootless UID mapping and SELinux labels affect bind mounts more often because the source already belongs to the host filesystem. Named volumes simplify many container-owned data cases but do not replace permission troubleshooting when something still fails. Use the decision tree above, then open Podman volumes for volume commands or Fix Podman volume permission denied when access errors appear.

