| 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; most volume commands work rootless, but host-side podman volume mount may require podman unshare |
| Scope | Creating and managing Podman-managed volumes — volume create/ls/inspect/rm/prune, named vs anonymous lifecycle, mounting with -v and --mount, copy-up, --uid/--gid, labels, host volume mount/unmount, volume export/import, and Podman 5 vs 6 prune behavior. Does not cover bind-mount choice depth, SELinux or UID permission troubleshooting, or storage.conf layout. |
| Related guides | Install Podman on RHEL |
A Podman volume is persistent storage Podman manages independently of any single container. Application data in a named volume survives container removal; another container can mount the same volume by name. This guide walks through creating volumes, mounting them, backing them up, and cleaning them up — without diving into bind mounts, SELinux labels, or storage-driver internals.
What is a Podman volume?
When a container writes under a mounted volume path, data lands in Podman-managed storage instead of the container writable layer:
Container
│
│ /data
▼
Podman named volume
│
▼
Host-managed volume storageThe writable layer is tied to one container and disappears when you remove that container (unless you commit it to a new image). A named volume is a separate object:
- You refer to it by name (
podman-volumes-data), not by guessing paths under Podman storage - It can outlive any one container
- Another container can mount the same volume at the same or a different path
- Podman chooses and manages the host location — you normally use
podman volume inspectwhen you need the mountpoint
Image archives from podman save do not include volume data. For that distinction, see Podman save, load, export and import.
Create a Podman volume
Create a named volume before you run a container:
podman volume create podman-volumes-dataPodman prints the volume name and stores a local driver volume. No container starts at this step.
List volumes to confirm:
podman volume lsSample output (truncated):
DRIVER VOLUME NAME
local podman-volumes-data
...local is the default driver on a normal Linux host. This guide focuses on the local driver; Podman can also use other supported volume drivers or configured volume plugins, whose backend-specific behavior is outside this lifecycle guide. Creating a volume prepares the storage but does not populate application data by itself. On first container use, Podman's default copy-up behavior may seed an empty volume with files already present at the image's mount destination; otherwise data appears when a workload writes to the volume.
Re-run creation safely in scripts with --ignore:
podman volume create --ignore podman-volumes-dataWhen the volume already exists, Podman prints the existing name and exits successfully. New options on that command are not applied to an existing volume — change labels or ownership only at first create, or remove and recreate the volume if you truly need different settings.
List Podman volumes
The default table shows driver and name:
podman volume lsFor scripts, quiet mode prints names only:
podman volume ls --quietSample output:
podman-volumes-data
podman-run-data
...Filter by name
Narrow a long list to volumes whose names match a substring:
podman volume ls --filter name=podman-volumesSample output:
DRIVER VOLUME NAME
local podman-volumes-dataFind unused volumes
Volumes not referenced by any container are dangling:
podman volume ls --filter dangling=trueSample output:
DRIVER VOLUME NAME
local 854477349e9801ec10831a9c3ab3634c6a0de87317e826a9520fd8dc4064b58b
...Long hash-like names often belong to anonymous volumes; use the .Anonymous field when you need to distinguish them reliably.
Filter by label
Labels set at create time are queryable metadata (not SELinux filesystem labels):
podman volume ls --filter label=environment=testSample output:
DRIVER VOLUME NAME
local podman-labeled-volumeNamed vs anonymous in the list
On Podman 5.8.2, podman volume ls does not accept an anonymous= filter. Use a custom format or inspect instead:
podman volume ls --format '{{.Name}} anonymous={{.Anonymous}}'Sample output:
854477349e9801ec10831a9c3ab3634c6a0de87317e826a9520fd8dc4064b58b anonymous=true
podman-volumes-data anonymous=falseVolumes with anonymous=true are anonymous volumes; anonymous=false identifies named volumes. Long hash-like names are common for anonymous volumes, but use the field rather than the name format when classification matters.
Inspect a Podman volume
podman volume inspect returns JSON metadata for one volume:
podman volume inspect podman-volumes-dataSample output:
[
{
"Name": "podman-volumes-data",
"Driver": "local",
"Mountpoint": "/var/lib/containers/storage/volumes/podman-volumes-data/_data",
"CreatedAt": "2026-08-22T22:45:50.252368481+05:30",
"Labels": {},
"Scope": "local",
"Options": {},
"MountCount": 0,
"NeedsCopyUp": true,
"NeedsChown": true,
"LockNumber": 0
}
]Fields worth knowing:
Name— volume identifier you pass to-vandpodman volumesubcommandsDriver— normallylocalMountpoint— host path to volume data (rootful layout shown above)Labels— Podman metadata from--labelat create timeMountCount— how many active mounts Podman currently tracks for the volumeNeedsCopyUp/NeedsChown— internal flags for first-use copy-up and ownership adjustmentAnonymous—truefor auto-generated anonymous volumes (visible on inspect even when not shown in defaultlsoutput)
Do not use MountCount to decide whether a volume is referenced by a container; podman volume rm behavior demonstrates that separately.
Pull just the mountpoint for scripts:
podman volume inspect --format '{{.Mountpoint}}' podman-volumes-dataSample output:
/var/lib/containers/storage/volumes/podman-volumes-data/_dataThat path is the right place to understand where data lives. For why rootful and rootless paths differ, and how storage.conf relocates storage, see Podman storage location — this article does not unpack graph-root layout.
Mount a named volume into a container
Write data through a container mount:
podman run --rm -v podman-volumes-data:/data docker.io/library/alpine:3.20 sh -c 'echo "persistent data" > /data/example.txt'Start a second container that reads the same volume:
podman run --rm -v podman-volumes-data:/data docker.io/library/alpine:3.20 cat /data/example.txtSample output:
persistent dataThe first container exited with --rm, but the named volume and its file remain. For one-off transfers between the host and a container path — including while the container is stopped — use copy files with podman cp instead of exec or a temporary mount.
The syntax breaks down as:
podman-volumes-data:/data
│ │
│ └── path inside the container
└── Podman volume nameBasic -v usage also appears in Run containers with podman run.
Named vs anonymous Podman volumes
Named volume
You choose the source name explicitly:
podman run --rm -v podman-volumes-data:/data docker.io/library/alpine:3.20 echo okA named volume:
- Has a stable name you can list and back up
- Persists after the container exits
- Is not removed by
podman run --rmalone - Is removed only when you
podman volume rmit (or prune it while unused)
Anonymous volume
Omit the source name and supply only a container path:
podman run --rm -v /data docker.io/library/alpine:3.20 sh -c 'echo anon > /data/anon.txt'Podman creates a randomly named volume internally. It still uses the volume driver — this is not a bind mount. With --rm, the anonymous volume is discarded when the container exits. Without --rm, the anonymous volume remains after the container exits. Removing the container normally does not remove it; use podman rm --volumes CONTAINER to remove anonymous volumes associated with that container, or prune them later. Named volumes are excluded from both container --rm and podman rm --volumes.
List volumes after creating anonymous ones without --rm and you will see hash-like names with anonymous=true in inspect output. That is expected — assign a name up front when you need data to survive and be easy to find.
Automatically create a named volume with -v
If the named volume does not exist, Podman creates it on first use:
podman run --rm -v automatically-created:/data docker.io/library/alpine:3.20 sh -c 'echo auto > /data/auto.txt'Confirm the new volume object:
podman volume ls --filter name=automatically-createdSample output:
DRIVER VOLUME NAME
local automatically-createdFor automation that must not silently create storage, create the volume explicitly first:
podman volume create automatically-createdPodman 6 adds a :nocreate mount option so podman run -v myvolume:/data:nocreate fails when myvolume is missing instead of creating it. That option is not available on the Podman 5.8.2 host used for this article (invalid option type "nocreate"). See Podman 5 to 6 migration when your distribution ships Podman 6.
-v vs --mount in Podman
Both attach a Podman-managed volume. Pick based on readability, not performance — both configure the same mount for the runtime.
-v
The short form names the volume and container path in one argument:
podman run --rm -v podman-volumes-data:/data docker.io/library/alpine:3.20 echo okShort and familiar if you already use Docker-style examples.
--mount
The structured form spells out type, source, and destination separately:
podman run --rm --mount type=volume,src=podman-volumes-data,dst=/data docker.io/library/alpine:3.20 echo okStructured key/value syntax — easier to read when several mount options appear together.
| Need | Recommended syntax |
|---|---|
| Simple named volume | -v is concise |
| Several mount options in one mount | --mount is clearer |
Scripts that spell out type=volume |
--mount |
| Familiar Docker/Podman examples | Either works |
Bind mounts, SELinux relabel options (:z, :Z), and permission failures belong in Bind mount vs volume and Fix Podman volume permission denied — not repeated here.
Read-only Podman volumes
Mount existing data read-only with :ro:
podman run --rm -v podman-volumes-data:/data:ro docker.io/library/alpine:3.20 cat /data/example.txtSample output:
persistent dataA write attempt fails at the filesystem level:
podman run --rm -v podman-volumes-data:/data:ro docker.io/library/alpine:3.20 sh -c 'echo fail > /data/ro-test.txt'Sample output:
sh: can't create /data/ro-test.txt: Read-only file systemThe same restriction in --mount form:
podman run --rm --mount type=volume,src=podman-volumes-data,dst=/data,ro docker.io/library/alpine:3.20 cat /data/example.txtHow named volume copy-up works
When a new named volume mounts over a directory that already contains files in the image, Podman can copy image contents into the volume on first use. That seeds configuration or default data without baking it into the volume object ahead of time.
Build a small image with content under /seed:
podman build -t localhost/copyup-demo:v1 -f - . <<'EOF'
FROM docker.io/library/alpine:3.20
RUN mkdir -p /seed && echo seeded-content > /seed/default.txt
EOFCreate a fresh volume and mount it over /seed:
podman volume create podman-copy-demoMount the empty volume over the image directory that already contains default.txt:
podman run --rm -v podman-copy-demo:/seed localhost/copyup-demo:v1 cat /seed/default.txtSample output:
seeded-contentThe image file was copied into the empty volume on first mount. Copy-up runs once per volume when applicable — not on every subsequent container start.
Disable copy-up with the nocopy mount option on Podman 5.8.2:
podman volume create podman-nocopy-demopodman run --rm \
-v podman-nocopy-demo:/seed:nocopy \
localhost/copyup-demo:v1 \
ls -la /seedSample output:
total 8
drwxr-xr-x 2 root root 4096 Mar 15 2024 .
drwxr-xr-x 1 root root 4096 Mar 15 2024 ..nocopy disables the normal first-use copy-up, so image files already present under /seed are hidden by the empty volume rather than copied into it.
Inspect the volume directly on the host when you need to verify files without a container:
podman volume mount podman-copy-demoSample output:
/var/lib/containers/storage/volumes/podman-copy-demo/_dataList the directory, then release the host mount:
ls -la /var/lib/containers/storage/volumes/podman-copy-demo/_dataRelease the host mount when you are finished inspecting files:
podman volume unmount podman-copy-demoSet volume ownership with --uid and --gid
Set ownership applied when the volume mountpoint is created:
podman volume create --uid 1000 --gid 1000 podman-owned-volumeVerify the stored values:
podman volume inspect podman-owned-volume --format 'UID={{.UID}} GID={{.GID}} Name={{.Name}}'Sample output:
UID=1000 GID=1000 Name=podman-owned-volume--uid and --gid on podman volume create are not the same as driver mount options such as --opt o=uid=1000, which pass filesystem mount options to the local driver. When processes inside the container cannot read or write the volume, the diagnostic tree lives in Fix Podman volume permission denied — not in this volume lifecycle guide.
Volume labels
Attach metadata at create time:
podman volume create --label application=demo --label environment=test podman-labeled-volumeFilter the list by label:
podman volume ls --filter label=environment=testThese labels are Podman object metadata for automation and filtering. They are unrelated to SELinux security contexts on the mounted files — both happen to use the word "label" in different contexts.
Mount and unmount a volume on the host
podman volume mount exposes the volume directory on the host for inspection or maintenance:
podman volume mount podman-volumes-dataSample output:
/var/lib/containers/storage/volumes/podman-volumes-data/_dataRead or back up files at that path, then unmount:
podman volume unmount podman-volumes-dataPrefer these commands over guessing paths under Podman storage. In rootless mode, podman volume mount generally needs to run inside the Podman user namespace. Enter it with podman unshare, then run podman volume mount VOLUME. Podman 5.8.2 documents file volumes as an exception. See Podman unshare when you need namespace-aware file operations.
Backup a Podman volume
Export volume contents to a tar archive:
podman volume export --output podman-volumes-data.tar podman-volumes-dataList archive members:
tar -tf podman-volumes-data.tarSample output:
example.txtpodman volume export archives files currently in the volume. For databases and other buffered applications, stop or quiesce the workload before export if you need a consistent on-disk snapshot. This section shows the mechanics — not database-specific backup procedures.
Restore a Podman volume
The destination volume must exist before import:
podman volume create restored-volumeImport the archive:
podman volume import restored-volume podman-volumes-data.tarVerify by mounting into a container:
podman run --rm -v restored-volume:/data docker.io/library/alpine:3.20 cat /data/example.txtSample output:
persistent datapodman volume import merges archive paths into the volume. It does not truncate the destination first. Add a file to the volume, then import a second archive:
podman run --rm -v restored-volume:/data docker.io/library/alpine:3.20 sh -c 'echo existing > /data/keep.txt'Build a small tar that adds only archive-only.txt:
echo 'archive-only' > /tmp/archive-only.txt && tar -cf /tmp/merge-test.tar -C /tmp archive-only.txtImport the second archive into the same volume:
podman volume import restored-volume /tmp/merge-test.tarAfter import, both the original example.txt, the locally added keep.txt, and archive-only.txt from the archive coexist. Overlapping paths take the archive content. Plan imports accordingly when you expected a full replace.
Copy data directly between volumes
Stream export into import when both volumes already exist:
podman volume create old-volumeCreate the destination volume before you import into it:
podman volume create new-volumeWrite a file into the source volume:
podman run --rm -v old-volume:/data docker.io/library/alpine:3.20 sh -c 'echo old-data > /data/file.txt'Pipe export output straight into import on the destination:
podman volume export old-volume | podman volume import new-volume -Confirm the copy:
podman run --rm -v new-volume:/data docker.io/library/alpine:3.20 cat /data/file.txtSample output:
old-datanew-volume must be created before the import on stdin — the same rule as file-based import.
Remove a Podman volume
Delete an unused volume by name:
podman volume rm podman-volumes-dataIf a container still references the volume, removal fails:
Error: volume podman-volumes-data is being used by the following container(s): 2977b356d041: volume is being usedStop and remove the container first, then remove the volume. podman volume rm --force is much more destructive: if containers use the volume, Podman removes those containers first and then removes the volume. Prefer removing or recreating the dependent containers explicitly so you know what is being deleted.
Prune unused Podman volumes
Unused volumes accumulate from forgotten containers and anonymous mounts. Prune behavior changed between major versions — confirm your Podman release before running this in production.
Podman 5.x (including 5.8.2 on this lab host)
On Podman 5.x, confirm the prompt carefully — prune is aggressive:
podman volume pruneremoves all unused volumes after confirmation, including unused named volumes. The help text states: "Remove all unused volumes. Note all data will be destroyed." On Podman 5.x, treating volume prune as safe housekeeping for only anonymous volumes is a mistake — named application data can be deleted if no container references it.
Podman 6.x
Podman 6 aligns closer to Docker defaults:
podman volume pruneremoves only unused anonymous volumespodman volume prune --allincludes unused named volumespodman volume prune --dry-runpreviews candidates without deleting
If you migrate from Podman 5 to 6, re-read prune semantics — see Podman 5 to 6 migration.
Podman volume vs container writable layer
| Container writable layer | Podman volume |
|---|---|
| Tied to one container instance | Independent storage object |
| Removed with the container (unless committed to an image) | Can survive container removal |
| Suited to temporary runtime changes | Suited to persistent application data |
| Hard to reuse across containers intentionally | Mount the same name from any container |
Volumes solve persistence inside Podman-managed storage. Bind mounts, which attach an arbitrary host directory, are a separate mount type — see Bind mount vs volume when you need that comparison.
References
- podman-volume man page
- podman-run man page —
-vand--mount - Podman storage documentation
Summary
Podman volumes are named storage objects managed separately from container filesystems. You created podman-volumes-data, mounted it with -v podman-volumes-data:/data, and proved persistence by reading the same file from a second container after the first exited with --rm.
Named volumes use explicit names and survive ordinary container removal. Anonymous volumes appear as hash-like names, carry Anonymous=true in inspect output, and disappear with podman run --rm when only a container path was specified. Both -v and --mount type=volume attach the same driver-backed storage; choose whichever reads clearer in your script.
Copy-up seeds image directories into a new volume on first mount — useful for default configuration trees. Back up with podman volume export and restore with podman volume import into a volume that already exists; import merges rather than replacing the destination wholesale. Use podman volume mount when you need host-level access without starting a container.
On Podman 5.8.2, podman volume prune deletes every unused volume after confirmation, named or anonymous. Podman 6 narrows the default prune to anonymous volumes. Check your version before pruning on a host that holds production data, and route permission or SELinux mount failures to the dedicated troubleshooting guides rather than guessing at volume paths under storage roots.

