With Docker BuildKit you generate an SBOM by adding the SBOM attestation option to your build. In a multi stage build, only the final stage is scanned by default, so build time tools from earlier stages do not appear. Opt in with Dockerfile arguments if you want those stages or the build context included.
The basic command
docker buildx build --sbom=true --push -t registry.example.com/app:1.5.0 .
That is shorthand for an attestation of type sbom. The default scanner is the BuildKit Syft scanner plugin, built on Syft. You can replace it with another image that implements the BuildKit SBOM scanner protocol.
Which stage is described
| Setting | Effect |
|---|---|
| Default | Final stage only |
| Stage scan argument set to true in a stage | That stage is scanned too |
| Stage scan argument as a list of names | Those stages are scanned, if they are built |
| Context scan argument set to true | The build context is included |
Two details trip people up. Both arguments must be declared with ARG in the Dockerfile, since passing the flag only on the command line has no effect. And environment variables and variable substitution do not work for them.
FROM golang:1.24 AS build
ARG BUILDKIT_SBOM_SCAN_STAGE=true
RUN go build -o /app ./cmd/server
FROM gcr.io/distroless/static
COPY --from=build /app /app
Should you include the build stage?
It depends on the question you are answering.
- What is running in production? Final stage only. This is the default and what most buyers want.
- What did our build depend on? Include the build stage. This helps incident response if a compiler or build tool is later found compromised.
- What did we copy in from the repo? Include the context.
Many teams keep two files: the production SBOM they share, and a fuller one they keep internally.
Check before you push
Build with the local output option to write files to a folder instead of an image. You will get sbom.spdx.json, and one extra file per scanned stage named for the stage. Open it and confirm a few packages you expect.
After pushing, inspect with docker buildx imagetools inspect and a format template. The SBOM data is under the SBOM key, per platform if the image is multi platform.
What the attestation looks like
The output is a JSON encoded SPDX document wrapped in an in toto statement, in the SLSA style. If you copy files into the final image from a stage, an SBOM of the final stage alone may only see them as files, not as packages. For compiled languages, a tool that reads embedded build data from the binary can help.
Try it yourself
Click through it at your own pace, or open it full screen.
Look at how packages are grouped by layer and image, and think about which of those layers your SBOM should describe.
Quick check
Why are my compiler and build tools missing from the SBOM?
They live in an earlier stage, and only the final stage is scanned unless you opt in.
Can I set the stage scan option with a shell variable?
No. It must be an ARG in the Dockerfile. Variable substitution does not work for it.
Safeguard's SBOM and dependency scanning includes container image scanning, and a free scan is available at gold.safeguard.sh/scan.
Sources
Last reviewed: 19 October 2026.