Run docker compose config --images to print every image name your Compose files resolve to, one per line. Use docker compose images to list images used by containers that Compose has already created. Add --resolve-image-digests to config to pin tags to digests, so each SBOM maps to exact image content.
Two questions, two commands
Docker's documentation describes both commands.
| Command | What it answers | Needs running containers? |
|---|---|---|
docker compose config --images | Which image names do my files declare? | No |
| docker compose images | Which images do created containers use? | Yes, containers must exist |
The config command parses, resolves and renders the Compose file in canonical form. It merges files passed with -f, resolves variables and expands short notation. Its --images flag prints image names one per line, and --services prints service names. The images command lists images used by containers Compose has created, takes optional service names, and supports --format with table or json, plus -q for image IDs just.
The first command gives you the plan. The second gives you the fact. Differences between them are worth a look: a service might be declared but never started in your environment.
Why the merge step matters
Real projects layer override files and variables. A plain read of docker-compose.yml misses an image that an override file changes. Because config merges the files and resolves variables, its output reflects what would run for a given set of inputs. Run it with the same -f flags and environment your deployment uses.
Steps to build the inventory
- Run config with
--imagesusing your deployment's file list and variables. - Save the list with the commit hash of the repo.
- For each image, record the tag and then resolve a digest. The
--resolve-image-digestsflag pins tags to digests in the rendered output. - Generate an SBOM for each digest, not each tag.
- Store the SBOMs next to the list, keyed by digest.
- Compare with docker compose images on a running stack to find surprises.
Pitfalls
Tags move. A tag like latest may point at different content next week, which is why the digest is the stable key. Services built locally from a Dockerfile have no registry digest until built, so scan the build output.
Images in profiles that you did not enable can be missed. If your stack uses profiles, run the command once per profile you ship.
Also remember that a Compose file is not the whole story. Sidecars started by orchestration outside Compose, or images pulled at runtime by an application, will not appear.
A worked example
Take a project with a base file and a production override. The base file defines three services: a web front end built locally, an API pulled from a registry, and a database pulled from a registry. The override changes the API image tag and adds a metrics sidecar. This layout is invented to show how the commands differ.
| Step | Command idea | Result |
|---|---|---|
| Read the base file alone | Plain read of the YAML | Three images, with the old API tag |
| Render the merged config | docker compose config --images with both files | Four images, with the new API tag and the sidecar |
| List images in use | docker compose images after bringing the stack up | Images of created containers, which may differ if a service is not started |
The middle row is the one to trust for an inventory of intent. It uses the same files and variables that your deployment uses, so the sidecar is not missed.
Digests in practice
After you have the list, resolve each tag to a digest. Docker's docs describe --resolve-image-digests on the config command as pinning image tags to digests. Save that rendered output with your release. For each digest, generate or fetch an SBOM and file it under the digest. When a report says an image is affected, you can then find the exact SBOM without wondering which tag moved.
Local builds
A service built from a Dockerfile has no registry digest until it is built and, ideally, pushed. Scan the built image, and record the image ID that docker compose images can print with the quiet flag. Also keep the Dockerfile and the base image reference with the SBOM, because the base image carries many of the packages.
Profiles and optional services
If your Compose file uses profiles, a plain run lists services in the default profile. Run the command once for each profile that exists in production. Otherwise a rarely used service, such as a migration job or an admin tool, escapes the inventory.
Environment variables
Image tags are often set with variables, for example a tag taken from the environment. The config command resolves variables, so run it with the same environment as the deployment. A variable that is unset on your laptop may fall back to a default that is not what production uses.
What the inventory does not cover
Compose describes containers on one host or one project. It does not describe images pulled by an orchestrator you run elsewhere, images pulled at runtime by your own code, or base images of images you solely reference. Keep a separate inventory for those, and avoid claiming that the Compose list is the whole estate.
Putting it in CI
- Run the config command with the production files and variables.
- Save the image list as an artifact with the commit hash.
- Resolve digests.
- Generate or look up an SBOM for each digest.
- Fail the job if any image lacks an SBOM or digest.
- Compare the list with the previous release and flag new images for review.
Reviewing the diff
The most valuable review is the diff between two image lists. A new image, a changed registry, or a tag moved to a different major version are all worth a human look. The list is short, so the review is quick, and it catches changes that dependency diffs inside images would not.
Try it yourself
Click through it at your own pace, or open it full screen.
Look at how an image breaks down into layers and packages.
Where Safeguard fits
Safeguard can scan container images and SBOMs, and the free scan at gold.safeguard.sh/scan lets you try one image from your list.
Quick check
Does docker compose config --images start containers?
No. It renders the resolved configuration and prints image names. Docker's docs describe it as parsing and rendering the file.
Why pin to digests?
A tag can point to different content over time. A digest identifies exact content, so the SBOM stays tied to what ran.
How do I get an image ID for a locally built service?
Run docker compose images with the quiet flag after the stack is created. It shows image IDs solely.
Sources
Last reviewed: 19 October 2026.