Thought Leadership
Oct 10, 2025

SPDX vs CycloneDX: Choosing the Right SBOM Format for Your Software Supply Chain

A clear, practical guide comparing SPDX and CycloneDX — their strengths, tools, and use cases — so you can pick the SBOM format that fits your workflow.

Give me the TL;DR
SPDX vs CycloneDX: Choosing the Right SBOM Format for Your Software Supply Chain
For Qualys admins, NES for .NET directly resolves the EOL/Obsolete Software:   Microsoft .NET Version 6 Detected vulnerability, ensuring your systems remain secure and compliant. Fill out the form to get pricing details and learn more.

Now that you know what an SBOM is, let’s dive in into the different formats of SBOMs you could encounter, and see which one is the more appropriate for your use case.

While there are less known and used SBOM formats*, there are two dominant standards: SPDX and CycloneDX. These standards have evolved into implementations of the NTIA (National Telecommunications and Information Administration) 's "minimum elements" plus some extensions.

SPDX (Software Package Data Exchange)

SPDX is a standard developed under the Linux Foundation Open Compliance Program.

SPDX is particularly strong in license compliance, offering detailed fields to capture complex licensing information. 

It supports various file formats like RDF/XML, JSON, and YAML

Its current latest version is 3.0, many tools, such as the SPDX maven plugin still rely on 2.3 though.

Strength: Licensing

Tools to generate SPDX SBOMs

Tool
Example, simple way to use it
Supported input types
SPDX version(s) supported
syft <image-or-dir> -o spdx-json > sbom.spdx.json
Container images (OCI/Docker), filesystem directories, archives, package manifests (many ecosystems).
SPDX 2.2, 2.3 (JSON)
cdxgen -o sbom.spdx.json --format spdx-json
Container images (OCI/Docker), filesystem directories, package manifests (many ecosystems).
SPDX 2.2, 2.3 (JSON)
mvn spdx:createSPDX
Maven projects
SPDX 2.2 (Tag-Value, RDF, JSON)
trivy image --format spdx --output sbom.spdx alpine:3.15
Container images (OCI/Docker), filesystem directories
SPDX 2.2, 2.3 (JSON)
snyk sbom --file=app.jar --format=spdx2.3+json > sbom.spdx.json
Filesystem directories, archives, package manifests (many ecosystems).
SPDX 2.3 (JSON)
tern report -i myimage:tag -f spdx > sbom.spdx
Container images (OCI/Docker)
SPDX 2.2 (Tag-Value, JSON)
scancode --spdx-json -clp --output-file sbom.spdx.json /path/to/code
filesystem directories
SPDX 2.2, 2.3 (JSON), RDF
ort analyze && ort report -f SPDX
filesystem directories
SPDX 2.2, 2.3 (JSON, Tag-Value, RDF)
(UI / CLI) Export → SPDX (tag-value/JSON/RDF)
filesystem directories, archives
SPDX 2.2, 2.3 (Tag-Value, JSON, RDF)
(UI / API) Export SBOM → choose SPDX
Container images (OCI/Docker), repositories, archives
SPDX 2.2, 2.3 (JSON)
jfrog xr export-sbom ... (via API or CLI)
Container images (OCI/Docker), archives
SPDX 2.3 (JSON)
bitbake <recipe> -c do_create_spdx
Embedded Linux builds / Yocto recipes and archives.
SPDX 2.2 (Tag-Value, JSON, RDF)

CycloneDX

CycloneDX is the other widely adopted SBOM standard, developed by the OWASP Foundation

CycloneDX focuses on creating a security context for software components. It is designed to facilitate vulnerability identification and outdated dependency analysis.

The specification extends beyond software libraries to standards such as software as a service bill of materials (SaaSBOM), Vulnerability Exploitability Exchange (VEX), and more. 

It supports various file formats like XML, JSON, and Protocol Buffers.

Its current latest version is 1.6.1, although many tools such as Paketo Buildpacks and the CycloneDX Maven plugin still rely on 1.6.

Strength: Vulnerability Identification

Tools to generate CycloneDX SBOMs

Tool
Example, simple way to use it
Supported input types
CycloneDX version(s) supported
syft packages alpine:3.18 -o cyclonedx-json
Container images (OCI/Docker), filesystem directories, archives, package manifests (many ecosystems).
v1.4, v1.5 (JSON, XML)
Trivy
trivy image --format cyclonedx --output sbom.json alpine:3.18
Container images (OCI/Docker), filesystem directories
v1.4, v1.5 (JSON)
snyk sbom --format=cyclonedx2.0 --file=myapp.jar
Filesystem directories, archives, package manifests (many ecosystems).
v1.2, v1.3, v1.4, v1.5 (JSON)
grype alpine:3.18 -o cyclonedx-json
Container images (OCI/Docker), filesystem directories, archives
v1.4, v1.5 (JSON)
mvn cyclonedx:makeAggregateBom
Maven projects
v1.3, v1.4, v1.5 (XML/JSON)
gradle cyclonedxBom
Gradle projects
v1.3, v1.4, v1.5 (XML/JSON)
npx @cyclonedx/bom
npm/yarn projects
v1.3, v1.4, v1.5 (JSON)
cyclonedx-py requirements -j -o bom.json
Python projects (pip, Poetry, requirements.txt)
v1.3, v1.4, v1.5 (JSON)
cyclonedx-gomod app -o bom.json
Go modules
v1.3, v1.4, v1.5 (JSON)
pack build myapp --buildpack paketo-buildpacks/java (SBOM auto-generated in /cnb/sbom)
Application builds into OCI container images (Java, Node.js, Go, etc.)
v1.4, v1.5 (JSON)

Comparison of SPDX and CycloneDX formats

Let’s take a dependency found in Spring PetClinic 2.7.18, the popular caching library ehcache (a transitive dependency in this context) and see how it’s represented in both formats (both JSON files were generated from their Maven plugins) - please note that some other tools could still analyze the same project but come up with different information (as described in the previous chapters, some tools work with a container image, some others with filesystems, etc.)

SPDX representation of the package:

1    {
2      "SPDXID": "SPDXRef--5a0de17c0",
3      "copyrightText": "UNSPECIFIED",
4      "description": "End-user ehcache3 jar artifact",
5      "downloadLocation": "NOASSERTION",
6      "externalRefs": [
7        {
8          "referenceCategory": "PACKAGE-MANAGER",
9          "referenceLocator": "pkg:maven/org.ehcache/ehcache@3.10.8",
10          "referenceType": "purl"
11        }
12      ],
13      "filesAnalyzed": false,
14      "homepage": "http://ehcache.org",
15      "licenseConcluded": "NOASSERTION",
16      "licenseDeclared": "Apache-2.0",
17      "name": "Ehcache",
18      "originator": "Organization:Terracotta Inc., a wholly-owned subsidiary of Software AG USA, Inc.",
19      "summary": "End-user ehcache3 jar artifact",
20      "versionInfo": "3.10.8"
21    },

CycloneDX representation of the package:

 {
      "type" : "library",
      "bom-ref" : "pkg:maven/org.ehcache/ehcache@3.10.8?type=jar",
      "publisher" : "Terracotta Inc., a wholly-owned subsidiary of Software AG USA, Inc.",
      "group" : "org.ehcache",
      "name" : "ehcache",
      "version" : "3.10.8",
      "description" : "End-user ehcache3 jar artifact",
      "scope" : "required",
      "hashes" : [
        {
          "alg" : "MD5",
          "content" : "35f94bd99bae66088df39d8a45e73468"
        },
        {
          "alg" : "SHA-1",
          "content" : "f0d50ede46609db78413ca7f4250d348a597b101"
        },
        {
          "alg" : "SHA-256",
          "content" : "bed87f71d8cd25a8a4ef65f274cc58301f28929a01417d0bee8d73953dc30bac"
        },
        {
          "alg" : "SHA-512",
          "content" : "deeafba63b4ff08f26721aa9b8582c486d4a12ad3889c3deadb52ca86cd71212550ffd71f7cefc8e58543fd0114f48cc086ec3c173091ea7a5c2f99a3919893e"
        },
        {
          "alg" : "SHA-384",
          "content" : "30be38713902e6c68cf32cc9ef5cf0a384d0dcacbe5d32e7dbdd8483c2f7002cadc68005a50084f1b56386e456023fc6"
        },
        {
          "alg" : "SHA3-384",
          "content" : "e349f39ae5a621ef760f7de6fde8a35140cb2a004d05653c9340779469dd61b18a0b8310c2a01b82cc02839bff58b7f0"
        },
        {
          "alg" : "SHA3-256",
          "content" : "6808204bcd31027ce377ecf6ece07ae9a39e209524201064663693cf763d6d3c"
        },
        {
          "alg" : "SHA3-512",
          "content" : "e0c691bdcdcd98b349b409fc0a0b7851a90090d71492cf882104007cea9adf2905e6ab59ba62d3241d4eff929beaf92eef09e7450cf58897b07f60fa30092992"
        }
      ],
      "licenses" : [
        {
          "license" : {
            "id" : "Apache-2.0"
          }
        }
      ],
      "purl" : "pkg:maven/org.ehcache/ehcache@3.10.8?type=jar",
      "externalReferences" : [
        {
          "type" : "website",
          "url" : "http://ehcache.org"
        },
        {
          "type" : "issue-tracker",
          "url" : "https://github.com/ehcache/ehcache3/issues"
        },
        {
          "type" : "vcs",
          "url" : "https://github.com/ehcache/ehcache3"
        }
      ]
    },

Few remarks about those SBOM entries:

  • Most of the data was recovered from the published pom (official web page URL, license, publisher)
  • Both SBOMs describe the same essential component and share several overlapping attributes:
  • Name & Version
    • SPDX: "name": "Ehcache", "versionInfo": "3.10.8"
    • CycloneDX: "name": "ehcache", "version": "3.10.8"
  • Description / Summary
    • SPDX: "description": "End-user ehcache3 jar artifact"
    • CycloneDX: same text in "description".
  • Homepage / Website
    • SPDX: "homepage": "http://ehcache.org"
    • CycloneDX: appears under "externalReferences": [{ "type": "website" … }].
  • Publisher / Originator
    • SPDX: "originator": "Organization:Terracotta Inc.…"
    • CycloneDX: "publisher": "Terracotta Inc.…".
  • License
    • SPDX: "licenseDeclared": "Apache-2.0"
    • CycloneDX: "licenses": [{ "license": { "id": "Apache-2.0" } }].
  • Package URL (purl)
    • SPDX: via externalRefs with referenceType: purl.
    • CycloneDX: native "purl" field, also reused in "bom-ref".
  • So both encapsulate: what it is, who makes it, what version, what license, where it lives, and its unique identifier.
  • The purl is probably the most important information that identifies precisely what the component is; in our case, pkg:maven/org.ehcache/ehcache@3.10.8
    • scheme: the scheme is always pkg, indicating a package URL
    • type: the package type or ecosystem, such as npm, maven, pypi, nuget, go, etc.
    • name:can be namespaced, here it’s org.ehcache/ehcache which is groupId/artifactId
    • version: 3.10.8
    • Qualifiers and subpath can optionally be added, for example the CycloneDX SBOM added the ?type=jar qualifier (as opposed to war or ear)

The Bottom Line

Which one should you opt for? 

As you can see, the most important information is included in both formats so it’s probably not liability to choose one over the other (with that said, I do like the extensibility and frequent updates to CycloneDX…); so you should rather choose the tool that best suits your development lifecycle to export your SBOM.

Maven / Gradle centric? Choose one of the plugins.

CI/CD centric? Why not use syft and its github action 

Made the switch to PaaS like workflow with buildpacks? Just rely on Paketo Buildpacks SBOM generation

Bought a fully fledged solution like BlackDuck or Snyk? No worries, they do support SBOM exports.

*  What about the lesser known (and oftentimes deprecated) SBOM formats?

Open format BOMS

Paketo Buildpack specific format for example: only used in the context of older Paketo Buildpacks, before CycloneDX and SPDX became popular

Syft JSON: It’s the Syft SBOM generator too (syft CLI)l native format, but it’s mainly used by Syft internally to capture all the information available in both SPDX and CycloneDX formats

SWID (Software Identification Tags): an ISO standard, XML only, very rarely encountered, even if it’s still mentioned on NIST (National Institute of Standard and Technology) website.

Proprietary format BOMs

Black Duck, WhiteSource (Mend.io), JFrog Xray — but these don’t leave their ecosystems.

Links: What is a software build of materials by BlackDuck

Table of Contents
Author
Anthony Dahanne
Software Engineer
Open Source Insights Delivered Monthly