- SBOM
- CycloneDX
- SPDX
CycloneDX vs SPDX: which SBOM format to use, and when it matters
Use CycloneDX for container and Kubernetes vulnerability work, SPDX for licence compliance or when a customer asks for it. Here is why, and what regulators accept.
StackRadar Team
6 min read
Both formats are international standards, both are accepted by every regulator that has expressed a view, and both can list the packages in a container image. The choice still matters, because it decides which tools can read your SBOMs and which compliance checklists they pass.
Where each one came from
SPDX (Software Package Data Exchange) started at the Linux Foundation in 2010 to solve licence compliance: which licences apply to which files in a distribution, precisely enough to satisfy a lawyer. That heritage shows in its depth on files, snippets, licence expressions and copyright text. SPDX 2.2.1 became ISO/IEC 5962:2021. SPDX 3.0 (April 2024, now 3.0.1) rebuilt the model around profiles, including a security profile, and is going through ISO as the next edition of 5962.
CycloneDX started in the OWASP community in 2017, explicitly for security and supply-chain use. It models components, services and dependency graphs, and carries vulnerability disclosures (VDR) and exploitability statements (VEX) natively. It is standardised as ECMA-424: version 1.6 was the first edition (June 2024), and 1.7, released in October 2025, the second.
What each one is good at modelling
| SPDX 2.3 / 3.0 | CycloneDX 1.6 / 1.7 | |
|---|---|---|
| Package inventory with versions | Yes | Yes |
| Package identifiers (PURL, CPE) | Via external references | First-class fields |
| Dependency graph | Relationships (many types) | dependencies[], simple and direct |
| File-level detail, snippets | Deep | Basic |
| Licence expressions | Deep (its origin) | Adequate |
| Vulnerabilities in the document (VDR) | 3.0 security profile | Native since 1.4 |
| Exploitability statements (VEX) | Separate (OpenVEX), or 3.0 | Native |
| Services, APIs | No | Yes |
| Serialisations | 2.3: tag-value, JSON, YAML, RDF, spreadsheet. 3.0: JSON-LD | JSON, XML, protobuf |
| Standard | ISO/IEC 5962:2021 (SPDX 2.2.1) | ECMA-424 (1st ed. 1.6, 2nd ed. 1.7) |
For vulnerability work, the identifier row decides it. A matcher works from a package URL (PURL): pkg:apk/alpine/nginx@1.27.5-r1?distro=alpine-3.21.3 carries the ecosystem, the distro and the exact version that an advisory's affected range is evaluated against. CycloneDX gives every component a dedicated purl field; SPDX carries it as one external reference among several. Both work, but only one was designed for it.
The same package in both
This is how Syft writes one Alpine package in each format.
{
"type": "library",
"name": "nginx",
"version": "1.27.5-r1",
"purl": "pkg:apk/alpine/nginx@1.27.5-r1?arch=x86_64&distro=alpine-3.21.3",
"cpe": "cpe:2.3:a:nginx:nginx:1.27.5-r1:*:*:*:*:*:*:*",
"licenses": [{ "license": { "id": "BSD-2-Clause" } }]
}{
"SPDXID": "SPDXRef-Package-apk-nginx-3c9251e68aafb845",
"name": "nginx",
"versionInfo": "1.27.5-r1",
"downloadLocation": "NOASSERTION",
"licenseConcluded": "NOASSERTION",
"licenseDeclared": "BSD-2-Clause",
"externalRefs": [
{ "referenceCategory": "SECURITY", "referenceType": "cpe23Type",
"referenceLocator": "cpe:2.3:a:nginx:nginx:1.27.5-r1:*:*:*:*:*:*:*" },
{ "referenceCategory": "PACKAGE-MANAGER", "referenceType": "purl",
"referenceLocator": "pkg:apk/alpine/nginx@1.27.5-r1?arch=x86_64&distro=alpine-3.21.3" }
]
}The facts are the same and only the shape differs. The CycloneDX reference has a complete, real document to read alongside the fragment above.
What the regulators actually say
- EU Cyber Resilience Act. Annex I requires manufacturers to draw up an SBOM "in a commonly used and machine-readable format covering at the very least the top-level dependencies". No standard is named. Article 13(24) lets the Commission specify a format by implementing act, but none had been adopted when this post was updated. The SBOM obligation applies from 11 December 2027; the CRA post covers the detail.
- United States. CISA, the NSA and international partners published the 2026 Minimum Elements for an SBOM in July 2026, replacing NTIA's 2021 list. It recommends SPDX and CycloneDX and drops the SWID tags the 2021 list also allowed.
- Germany (BSI TR-03183-2). Version 2.1.0 (August 2025) accepts either format, but only CycloneDX 1.6 or later, or SPDX 3.0.1 or later, in JSON or XML. An SPDX 2.3 document does not meet it.
The pattern is consistent: regulators specify content and let you pick the container. That content is supplier, name, version, unique identifier, dependency relationships, author and timestamp, and CISA's 2026 list adds licence and hash. Both formats can carry all of it.
Tool support: SPDX 3 is the gap
In practice the version you can generate matters more than the format. Syft, the open-source generator that BuildKit and StackRadar both build on, writes CycloneDX up to 1.6 and SPDX 2.2 and 2.3, but not SPDX 3. Docker BuildKit's --sbom attestations are SPDX 2.3, produced by Syft. So a team that needs BSI conformance can get it from Syft today with CycloneDX, but not with SPDX.
On the consuming side, Dependency-Track and Trivy Operator are built around CycloneDX, while Grype, Trivy and OSV-Scanner read both. StackRadar is on the CycloneDX side too: it keeps a CycloneDX 1.6 SBOM for every running image, validated against the official schema, and does not ingest SPDX uploads. The SBOM tools comparison covers the generators themselves.
How to decide
- Someone else specifies it. A customer contract, a procurement questionnaire, a platform you upload to. Do what they say, and generate that format directly rather than converting. Check the version too: "SPDX" under BSI TR-03183-2 means 3.0.1.
- Vulnerability tracking is the main use. CycloneDX. You get native PURLs, a simple dependency graph, and VEX in the same document when you need it.
- Licence compliance is the main use. SPDX. File-level detail and licence expressions are what it was built for.
- Both. Emit both from one scan. Syft accepts several outputs in one run, so the cost is one extra file per image:
syft nginx:1.27 \
-o cyclonedx-json=nginx.cdx.json \
-o spdx-json=nginx.spdx.jsonThat covers one image. To see a CycloneDX SBOM kept for every image a cluster is running, open the live demo, which needs no account, or read how it works on the Kubernetes SBOM page.
Frequently asked questions
What is the difference between CycloneDX and SPDX?
Both are machine-readable SBOM standards. SPDX (Linux Foundation, ISO/IEC 5962:2021) began in 2010 as a licence-compliance format and models packages, files, snippets and their licences in depth. CycloneDX (OWASP, ECMA-424) was designed from 2017 for security: package URLs are a first-class field on every component, and vulnerability (VDR) and exploitability (VEX) data live in the same document. Both express a basic package inventory equally well.
Which SBOM format do regulators require?
None mandates one. The EU Cyber Resilience Act asks for a "commonly used and machine-readable format" and names no standard. CISA’s 2026 minimum elements, which replace the 2021 NTIA list, recommend SPDX or CycloneDX. Germany’s BSI TR-03183-2 accepts both but sets minimum versions: CycloneDX 1.6 or SPDX 3.0.1, in JSON or XML.
Is CycloneDX or SPDX more common for container images?
CycloneDX is the format most container security tooling is built around: Dependency-Track ingests CycloneDX, Trivy Operator stores its SBOM reports as CycloneDX, and StackRadar ingests CycloneDX 1.6. Syft and Trivy write both formats. SPDX is the norm in Linux distribution and Linux Foundation projects, and Docker BuildKit writes SBOM attestations as SPDX.
Can I convert between CycloneDX and SPDX?
Yes, with some loss. The CycloneDX CLI and SPDX tooling can convert existing documents, but fields that exist in one model and not the other (VEX statements, SPDX snippets, annotations) do not survive a round trip. If a customer needs a specific format, generate it from the image directly rather than converting.
Should I use CycloneDX 1.6 or 1.7?
For a container inventory, 1.6 is enough and has the widest tool support. Syft writes up to 1.6, and 1.6 is the minimum BSI TR-03183-2 accepts. CycloneDX 1.7 (October 2025, ECMA-424 2nd edition) is backward compatible and mainly adds cryptography, citation and intellectual-property metadata that vulnerability matching does not use.
What is SPDX 3.0?
SPDX 3.0, released in April 2024 (3.0.1 followed in December 2024), rebuilt the standard as a graph of elements organised into profiles (core, software, security, licensing, build, AI, dataset) and serialised as JSON-LD. Its security profile narrows the gap with CycloneDX. Generator support is still thin: Syft, for example, writes SPDX 2.2 and 2.3 only.
More from the blog
All postsSBOM tools compared: Syft, Trivy, Docker Scout, cdxgen and cluster-level SBOMs
Syft, Trivy, Docker Scout and cdxgen compared: the current command for each, where each is best, and why an SBOM of what your cluster runs needs a different tool.
8 min read
What the EU Cyber Resilience Act means for your Kubernetes SBOMs
CRA reporting has applied since 11 September 2026; the SBOM requirement follows on 11 December 2027. Who is in scope and what Kubernetes teams need.
7 min read
StackRadar is open source: a self-hosted Kubernetes vulnerability dashboard under AGPL-3.0
The server, the dashboard and the Helm chart are on GitHub under AGPL-3.0, the scanner and CLI under Apache-2.0. One Helm command installs the lot in your cluster, with no telemetry and nothing leaving it. What is open, why these licences, and where the cloud fits.
8 min read
A new CVE should not need a new scan: how we keep 900,000 advisories current
Most scanners match an image once, when it is scanned. We mirror OSV.dev every hour, EPSS and KEV every day, and re-match every stored SBOM when the mirror changes. How, and what it does not solve.
10 min read