Manage Container Images with Podman

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; flags behave the same rootless unless noted
Scope Managing images already in local Podman storage — podman images, listing options, filters, tag, untag, rmi, image prune, history, and image tree. Does not cover pulling, building, registry push, signing, full podman inspect, or podman system prune.
Related guides Run containers with podman run
Build images with podman build
Install Podman on RHEL

This page covers images that are already on disk. Pulling, building, and registry push belong in other lessons; here the lab uses two locally built images named localhost/demo:v1 and localhost/demo:v2 plus the UBI base they share.


List Podman images

The default listing shows locally stored images while hiding intermediate image layers. Use -a or --all to include intermediate layers; dangling <none> rows can still appear.

bash
podman images

Sample output:

output
REPOSITORY                                   TAG         IMAGE ID      CREATED         SIZE
localhost/demo                               v2          9069ee56f492  56 seconds ago  109 MB
localhost/demo                               v1          0addc8fd8ded  59 seconds ago  109 MB
registry.access.redhat.com/ubi9/ubi-minimal  latest      591c6dfb4400  4 days ago      109 MB

The same data is available as podman image ls or podman image list. This article uses podman images because that is the phrase most readers search for.

Each row is a name pointing at a local image object. The image ID identifies that object in your storage. Repository and tag are human-readable references; they are not the same thing as a registry digest from a remote manifest.


Show image digests, IDs, and listing shortcuts

Add --digests when you need the manifest digest Podman stored with the image:

bash
podman images --digests --filter reference=localhost/demo

Sample output:

output
REPOSITORY      TAG         DIGEST                                                                   IMAGE ID      CREATED         SIZE
localhost/demo  v2          sha256:393e07e3f3b233b2bafb2ed2e3942852df2017bd1b48ae6437480a8915cbd9ce  9069ee56f492  56 seconds ago  109 MB
localhost/demo  v1          sha256:4c094b5cfb7f9857e71b96d7c8c1470b90a594d7c9dc96ff962bdbe4d44c5b8c  0addc8fd8ded  59 seconds ago  109 MB

A digest identifies image content in registry workflows. The short image ID is what you use in day-to-day local commands. They are related but not interchangeable.

Show full image IDs when scripts need the complete hash:

bash
podman images --no-trunc --filter reference=localhost/demo

For loops and cleanup scripts, print IDs only:

bash
podman images -q --filter reference=localhost/demo

Sample output:

output
9069ee56f492
0addc8fd8ded

Filter and sort Podman images

Filters turn podman images into a targeted lookup instead of a full table dump.

Find dangling images — untagged and unreferenced by another image:

bash
podman images --filter dangling=true

Sample output:

output
REPOSITORY  TAG         IMAGE ID      CREATED        SIZE
<none>      <none>      74cee6938c01  3 seconds ago  109 MB

Dangling rows usually appear after you rebuild the same tag and the old image ID loses its name.

Match a reference pattern:

bash
podman images --filter reference='localhost/demo*'

Filter by label set at build time:

bash
podman images --filter label=environment=test

List images older than another local image:

bash
podman images --filter before=localhost/demo:v2

List images newer than a reference image:

bash
podman images --filter since=localhost/demo:v1

Sort output by column name:

bash
podman images --filter reference='localhost/demo*' --sort repository

Useful sort keys include created, id, repository, size, and tag. The manifest=true filter lists manifest-list images when you work with multi-arch references; the lab host had none at capture time.


Tag a Podman image

Tagging adds another name to the same local image. It does not copy every layer to a second image object.

Add a release name beside the existing v1 tag:

bash
podman tag localhost/demo:v1 localhost/demo:release

Prepare a registry-style name without pushing anything:

bash
podman tag localhost/demo:v1 registry.example.com/project/demo:v1

Confirm both names share one image ID:

bash
podman images --format "table {{.Repository}}\t{{.Tag}}\t{{.ID}}" | grep -E 'demo|project'

Sample output:

output
localhost/demo                               v2          9069ee56f492
registry.example.com/project/demo            v1          0addc8fd8ded
localhost/demo                               release     0addc8fd8ded
localhost/demo                               v1          0addc8fd8ded

A tag is normally name:tag. When you omit the tag, Podman defaults to latest. Tagging only updates local references; nothing is sent to a registry until you push in a separate step.


Remove an image tag with podman untag

podman untag drops a name from local storage. podman rmi deletes the image object when nothing else needs it.

To remove one name while another tag on the same image ID stays, pass the image ID and the tag you want gone:

bash
V1ID=$(podman images -q localhost/demo:v1)

Pass the image ID and the tag name you want to remove:

bash
podman untag "${V1ID}" localhost/demo:release

The v1 tag remains while release disappears:

bash
podman images --format "table {{.Repository}}\t{{.Tag}}\t{{.ID}}" | grep -E 'demo|project'

Sample output:

output
localhost/demo                               v2          9069ee56f492
registry.example.com/project/demo            v1          0addc8fd8ded
localhost/demo                               v1          0addc8fd8ded

The same pattern works for registry-only names:

bash
podman tag localhost/demo:v1 registry.example.com/project/demo:v1

Drop only the registry name while keeping the local tag:

bash
podman untag "${V1ID}" registry.example.com/project/demo:v1

Afterward, only localhost/demo:v1 and localhost/demo:v2 remain in the listing. Untagging removes references, not necessarily every byte on disk, when a child image such as v2 still shares parent layers.


Remove Podman images with podman rmi

Delete a single image by name or ID:

bash
podman rmi registry.example.com/project/demo:v1

podman rmi prints Untagged for each name removed and Deleted when layer data is reclaimed.

Remove multiple images in one command:

bash
podman rmi localhost/demo:v1 localhost/dangle:v1

Remove every image Podman can delete:

bash
podman rmi --all

Treat podman rmi -a -f as a last resort. --force can also remove containers that still use those images. Prefer removing containers first, then trimming images.


Fix image removal errors

Image is used by a container

Start a container from localhost/demo:v2, then try to delete that image:

bash
podman run -d --name img-use-demo localhost/demo:v2 sleep 3600

With the container still present, image removal fails:

bash
podman rmi localhost/demo:v2

Sample output:

output
Error: image used by 9f80a392d235e5d1e88c7f3cefd53256b9ba6d88c8cb11fcba3b5d8cbd7cd130: image is in use by a container: consider listing external containers and force-removing image

The exit code is 2. Find containers created from that image:

bash
podman ps -a --filter ancestor=localhost/demo:v2 --format "table {{.Names}}\t{{.Status}}"

Sample output:

output
NAMES         STATUS
img-use-demo  Up Less than a second

Stop and remove the container, then run podman rmi again. Use -f only when you accept removing the running container with the image.

Image has child or dependent layers

Child images share parent layers. Before forcing deletion, inspect what still depends on a parent:

bash
podman image tree --whatrequires localhost/demo:v1

Sample output:

output
Image ID: 0addc8fd8ded
Tags:     [localhost/demo:v1]
Size:     108.7MB
Image Layers
└── ID: 338bc4464e57 Size:  2.56kB Top Layer of: [localhost/demo:v1]
    ├── ID: 71eca6f5bd72 Size:  2.56kB Top Layer of: [localhost/demo:v2]
    └── ID: 763777a11d18 Size:      0B

The --whatrequires output shows v2 depends on layers shared with v1. Remove or retag dependent images first when cleanup should stay predictable. Forcing podman rmi -f is an escape hatch, not the first diagnostic step.

Symptom Likely cause Fix
image is in use by a container A container still references the image podman ps -a --filter ancestor=IMAGE, remove containers, then podman rmi
Child image still listed in image tree --whatrequires Parent layers are shared Remove or retag child images first
image not known Name typo or tag already untagged podman images, fix the reference
podman rmi --all stops partway Some images still referenced by containers Remove containers or prune selectively

Understand Podman image layers with image history

podman history walks through the build steps that produced one image:

bash
podman history localhost/demo:v2

Sample output:

output
ID            CREATED             CREATED BY                                     SIZE        COMMENT
9069ee56f492  About a minute ago  /bin/sh -c echo v2 > /demo/version             2.56kB      FROM localhost/demo:v1
0addc8fd8ded  About a minute ago  /bin/sh -c mkdir -p /demo && echo v1 > /de...  2.56kB      
591c6dfb4400  About a minute ago  /bin/sh -c #(nop) LABEL environment=test       0B          FROM registry.access.redhat.com/ubi9/ubi-minimal:latest
<missing>     4 days ago          /bin/sh -c #(nop) LABEL "org.opencontainer...  109MB

The CREATED BY column shows the instruction behind each layer. Large jumps in SIZE highlight where an image grew. Add --no-trunc when you need full layer IDs and complete command text.

This is useful when an image is larger than expected or when you want to see which Containerfile step added a layer. It is not a full image-optimization guide.


View the image layer tree

podman image tree shows an image's layer hierarchy and annotates local tags on their top layers:

bash
podman image tree localhost/demo:v2

Sample output:

output
Image ID: 9069ee56f492
Tags:     [localhost/demo:v2]
Size:     108.7MB
Image Layers
├── ID: a17734aea26f Size: 108.7MB Top Layer of: [registry.access.redhat.com/ubi9/ubi-minimal:latest]
├── ID: 338bc4464e57 Size:  2.56kB Top Layer of: [localhost/demo:v1]
└── ID: 71eca6f5bd72 Size:  2.56kB Top Layer of: [localhost/demo:v2]

Use history when you care about build steps on one image. Use image tree when you need layer hierarchy and dependency relationships across images, especially before removing a shared base. Add --whatrequires to see which child images or layers still depend on the selected image.


Remove dangling and unused images

Default prune removes dangling images only:

bash
podman image prune

Sample output:

output
WARNING! This command removes all dangling images.
Are you sure you want to continue? [y/N]

Answer y to confirm. Podman prints one deleted ID per reclaimed dangling image.

Extend cleanup to every unused tagged image:

bash
podman image prune --all

Sample output:

output
WARNING! This command removes all images without at least one container associated with them.
Are you sure you want to continue? [y/N]

With a container still referencing localhost/demo:v2, prune --all removed other unused images while the tagged v2 row remained.

Age-based filtering works on prune:

bash
podman image prune --filter until=24h --force

Add --build-cache when you also want persistent build cache from cache mounts removed. For disk-usage overview and system-wide cleanup routing, see the system prune lesson when it ships; this page stays on image objects only.


Dangling images vs unused images

Readers often mix these terms:

A dangling image has no tag and is no longer referenced by another image. It commonly appears as <none>:<none> after rebuilds or untagging.

An unused image may still have a valid repository:tag name. It is simply not referenced by any existing container.

Therefore:

text
podman image prune       → dangling images only
podman image prune --all → every unused image, tagged or not

Prune --all is broader. Default prune is the safer first pass when you only want nameless leftovers.


podman images vs podman inspect

Need Command
List images podman images
Filter images podman images --filter
Image build and layer history podman history
Layer hierarchy and dependencies podman image tree
Detailed image configuration and metadata podman inspect

podman images answers what is stored and how large it is. podman inspect returns full JSON metadata for one object when you need every field.


References

Summary

You listed local images with podman images, added digests and ID-only output, and filtered by dangling state, labels, reference patterns, and relative age. Tagging gave the same image multiple names without duplicating layers; podman untag removed one name when you passed the image ID and the specific tag to drop.

podman rmi deletes image objects from storage, while containers block removal until you delete them or force the operation. podman history explains how one image was built; podman image tree shows layer hierarchy and which images or layers still depend on a shared base. Default podman image prune clears dangling untagged images; podman image prune --all reaches tagged images that no container uses.

When cleanup still leaves disk pressure, check running and stopped containers before reaching for rmi -a -f. Remove containers with podman rm and image pruning solve different layers of the same housekeeping problem.


Frequently Asked Questions

1. What is the difference between podman untag and podman rmi?

podman untag removes a name or tag reference from a local image. podman rmi deletes the image from local storage when no container or child image still needs it. Removing a tag does not always delete layer data; removing the image does.

2. What is a dangling Podman image?

A dangling image has no tag and is no longer referenced by another image. It commonly appears as none:none after rebuilds or untagging. podman image prune removes dangling images by default.

3. How do I remove all unused Podman images?

Run podman image prune --all and confirm the prompt. That removes images not referenced by any container. podman rmi --all deletes every image Podman can remove, which is more aggressive and can fail when containers still reference an image.

4. Why does podman rmi say the image is in use?

A container was created from that image and still exists, even if stopped. List dependents with podman ps -a --filter ancestor=IMAGE, remove or stop those containers, then run podman rmi again. Forcing with podman rmi -f also removes running containers using the image.

5. What is the difference between podman history and podman image tree?

podman history shows how one image was built layer by layer. podman image tree shows the image layer hierarchy and identifies local image tags that sit on those layers; --whatrequires exposes child images and layers that depend on the selected image.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)