The EU Cyber Resilience Act’s 24-hour reporting duty starts 11 September 2026. What it actually requires
SBOMcomparisonsSyft

SBOM tools compared: Syft, Trivy, docker sbom, and cluster-level SBOMs

How to generate an SBOM with Syft, Trivy, docker sbom, cdxgen and Docker Scout, what each is best at, and why a cluster-level SBOM of what is running is a different tool from any of them.

StackRadar Team

· 10 min read

There are more SBOM generators than there are good reasons to choose between them. For container images the field has effectively settled — Syft, Trivy, and the tools that wrap one or the other — and the interesting choices are elsewhere: build-time versus image-time, and single image versus everything a cluster runs. This post covers the generators you will actually meet, credits the one we built on, and explains why a cluster-level SBOM is a different tool from all of them.

Syft

Syft (Anchore, Apache-2.0) is the tool the rest of this post is measured against. It reads an image, a directory or a file, runs a set of catalogers — apk, dpkg, rpm, npm, pip, Go modules, Java archives, Rust, Ruby, PHP, .NET, binaries and more — and emits CycloneDX, SPDX or its own JSON.

bash
syft registry:docker.io/library/nginx:1.27-alpine --platform linux/amd64 \
  -o cyclonedx-json@1.6 > nginx.cdx.json

That exact command produced the downloadable example on our CycloneDX page: 68 Alpine packages, one operating-system component, 62 dependency edges, and 978 file entries recording binary evidence. It is also, with no changes, the generator inside the StackRadar scanner — we did not write our own, because Syft is better than anything we would have written and its output is what every matcher already understands. Credit where due: Anchore maintains it in the open, and it is the reason the SBOM ecosystem interoperates at all.

Strengths: the broadest cataloger set; deterministic; PURLs and CPEs on every component; converts between formats. Limits: it inspects the artefact, so it sees what was installed, not the full dependency graph the build resolved — a jar that shades its dependencies is one component, not fifty.

Trivy

Trivy (Aqua, Apache-2.0) is primarily a scanner, but --format cyclonedx or --format spdx-json turns any scan into an SBOM, and Trivy can scan an SBOM it or Syft produced.

bash
trivy image --format cyclonedx --output nginx.cdx.json nginx:1.27-alpine

Coverage of OS packages is comparable to Syft; language coverage is slightly narrower, and the two will produce different component counts on the same image — different catalogers, different opinions about what a "package" is in a Go binary. If you already run Trivy in CI and want an SBOM as a by-product, this is the zero-effort route. Trivy Operator emits the same documents in-cluster as SbomReport resources.

docker sbom and docker scout sbom

docker sbom shipped as an experimental CLI plugin in 2022 and is a thin wrapper around Syft; it still works, and its output is Syft's. Docker's current effort is docker scout sbom, which produces an SBOM as part of the Scout service and stores it against the image in Docker Hub. Use the Scout version if you are a Scout user; otherwise run Syft directly and avoid the plugin's experimental status.

bash
docker sbom nginx:1.27-alpine --format cyclonedx-json > nginx.cdx.json
docker scout sbom --format cyclonedx nginx:1.27-alpine

cdxgen

cdxgen (OWASP CycloneDX project, Apache-2.0) is the build-time generator: point it at a source tree and it resolves the dependency graph from the package manager — npm, Maven, Gradle, pip, Go, .NET and dozens more — producing CycloneDX with the full transitive tree, scopes, and evidence. For application code it is usually more complete than an image inspection, because it sees what the build resolved rather than what survived into the artefact. It does not cover the OS layer, and it can be slow and fragile on builds that need a specific toolchain present.

bash
cdxgen -t js -o bom.json ./checkout-service

The build-versus-image distinction is the real choice here. A build SBOM knows about devDependencies and build tools; an image SBOM knows about glibc and OpenSSL. For vulnerability tracking of production, the image SBOM is the one that matters — it is the artefact the kubelet runs — and the build SBOM is the one that answers licence and provenance questions. Many teams keep both and attach them to the image as attestations.

Others you will meet

  • BuildKit / docker buildx attestations --sbom=true at build time attaches a Syft-generated SBOM to the image manifest as an in-toto attestation. Good practice for images you build; irrelevant for the ones you pull.
  • Tern — layer-by-layer container inspection, Linux Foundation; slower and less maintained than Syft, but its per-layer attribution is unusual.
  • Language-native plugins — CycloneDX Maven/Gradle/npm plugins, pip-audit, cargo cyclonedx. Precise for one ecosystem, blind to everything else.
  • Snyk, Sysdig, Wiz, etc. — every commercial scanner exports an SBOM. Fine as a by-product; nobody chooses a platform for it.

The cluster-level SBOM is a different tool

Everything above takes an artefact you name and describes it. A cluster is not an artefact; it is a set of image digests that changes with every deploy, and roughly half of them are images nobody in your organisation built. A cluster-level SBOM tool has three jobs the generators do not:

  1. Discover the digests the kubelets are running — app containers, init containers, sidecars — and notice when they change.
  2. Generate once per digest, however many pods share it, using the pods' own pull secrets to reach private registries.
  3. Keep and attribute the result: one dated SBOM per image per cluster, tied to the namespaces, workloads, Helm releases and ArgoCD applications that run it, superseded rather than overwritten when the digest changes.

Trivy Operator does the first two and writes the result as a CRD with a 24-hour TTL, which is a reasonable answer for one cluster and no history. StackRadar does all three with Syft embedded in its scanner, keeps the SBOM outside the cluster, lets you download it per image, and re-matches it as advisories land. Building it yourself from Syft, a cron job and Dependency-Track is also a legitimate path — the generator is the easy part.

Whatever tool you pick, generate for linux/amd64 (or the platform your nodes run) explicitly. Syft and Trivy default to the host platform, and an SBOM from an Apple Silicon laptop describes an aarch64 image your cluster never runs.

Side by side

ToolInputFormatsOS packagesFull dependency graphWhole cluster
SyftImage, directory, fileCycloneDX, SPDX, Syft JSONYesPartial (what is installed)No
TrivyImage, filesystem, repoCycloneDX, SPDXYesPartialVia Trivy Operator
docker sbom / scout sbomImageCycloneDX, SPDX (Syft under the hood)YesPartialNo
cdxgenSource tree, some imagesCycloneDXLimitedYesNo
BuildKit attestationsBuildSPDX (Syft)YesPartialNo
Trivy OperatorRunning clusterCycloneDX (CRD)YesPartialOne cluster, 24h TTL
StackRadarRunning cluster(s)CycloneDX 1.6 (Syft)YesPartialEvery cluster, kept

Format choice — CycloneDX or SPDX — is a separate question with a shorter answer; CycloneDX vs SPDX covers it.

Frequently asked questions

How do I generate an SBOM for a container image?

Run Syft against the image reference: `syft nginx:1.27 -o cyclonedx-json > sbom.json`. Use `-o spdx-json` for SPDX. Syft pulls the image with your existing registry credentials, no Docker daemon required. Trivy (`trivy image --format cyclonedx nginx:1.27`) and the `docker sbom` plugin (which wraps Syft) produce equivalent output.

What is the best SBOM generation tool?

For container images, Syft is the most widely used and the reference most other tools wrap or compare against. For application source trees — a Node or Java project with its full dependency graph — cdxgen typically produces a more complete CycloneDX document because it resolves the build rather than inspecting the artefact. For a whole Kubernetes cluster, you need a tool that discovers running images and runs one of the above per image: Trivy Operator or StackRadar.

What is the difference between syft and grype?

Syft generates an SBOM — the inventory of packages in an image or directory. Grype reads an SBOM (or an image directly) and matches the packages against vulnerability databases. They are two halves of a pipeline from the same maintainer, Anchore, and the recommended workflow is Syft once, Grype whenever the database changes.

Does docker sbom still work?

The `docker sbom` CLI plugin, released as experimental in 2022, still works and still wraps Syft, but it has not been the focus of development; Docker’s current SBOM tooling is `docker scout sbom`, which is tied to the Scout service. For a stable, scriptable SBOM from an image, run Syft directly.

Should the SBOM come from the build or from the image?

Both are useful and they answer different questions. A build-time SBOM (cdxgen, a package-manager plugin, or BuildKit attestations) knows the full dependency graph including devDependencies and build tools. An image SBOM (Syft, Trivy) knows what actually shipped, including the OS layer. For vulnerability tracking of what runs in production, the image SBOM is the one that matters, because it is the artefact the kubelet runs.