start

SBOM formats

SPDX 2.3 vs. CycloneDX 1.6, when to pick which, ingest and conversion recipes.

Bomly reads and writes the two open SBOM standards used in production today: SPDX 2.3 and CycloneDX 1.6.

What's an SBOM?

A Software Bill of Materials is a structured list of every package in a piece of software, with enough metadata (versions, licenses, suppliers, hashes) for an outside tool to make decisions about it. It is the dependency graph as a portable file.

You produce an SBOM once and consume it many times: in PR checks, in release artifacts, in supplier audits, in attestation pipelines.

Format comparison

SPDX 2.3CycloneDX 1.6
StewardLinux FoundationOWASP
Primary use caseSoftware supply chain and license complianceComponent analysis and vulnerability management
Bomly write targetspdxcyclonedx
EncodingJSON (also Tag-Value and YAML upstream)JSON (also XML upstream)
Vulnerability dataAdd-on (SPDX 3.0)First-class (vulnerabilities array)
File hashesYesYes
Relationship edgesRich DESCRIBES, DEPENDS_ON, etc.dependencies graph
AdoptionNTIA reference, ISO/IEC 5962OWASP standard, broad scanner support

In practice: pick SPDX when a regulator or customer asks for it; pick CycloneDX when a vulnerability scanner is on the other end. Producing both is cheap.

Writing an SBOM

Use --format <format> for the primary stdout output, or -o <format>[=<path>] when you want an SBOM alongside another output. The format alone writes to stdout; format=path writes to a file:

# One format to stdout
bomly scan --format spdx

# One format to a file
bomly scan -o spdx=sbom.spdx.json

# Two formats in one scan
bomly scan \
  -o spdx=sbom.spdx.json \
  -o cyclonedx=sbom.cdx.json

# One format to stdout, one to a file
bomly scan -o spdx -o cyclonedx=sbom.cdx.json

Constraints:

  • At most one -o may omit =<path>. Two stdout outputs would collide.
  • -o spdx= (empty path) is an error.
  • --format spdx, --format cyclonedx, -o spdx, and -o cyclonedx are supported by scan only.
  • Paths are resolved relative to the current working directory.

Ingesting an SBOM

Skip detection entirely and load an existing SBOM as input:

bomly scan --sbom --path ./vendor.spdx.json

This is fast, offline, and useful for:

  • Auditing a vendor SBOM against your policy.
  • Re-running policy on an SBOM you produced in a previous CI step.
  • Diffing SBOMs across releases.

Format is auto-detected by content (both SPDX and CycloneDX JSON are supported).

Diffing SBOMs

Compare two SBOM files without re-running detectors on either side:

bomly diff --sbom --base ./v1.0.spdx.json --head ./v1.1.spdx.json

Useful for release notes, supplier-update reviews, and CI checks on prebuilt SBOMs.

What Bomly puts in the SBOM

Both formats carry:

  • Package name, version, PURL.
  • Dependency relationships from the detector graph.
  • File-level evidence when the detector provided it.

When --enrich is set, components are enriched from the matching-stage package registry (keyed by PURL):

  • Licenses learned during matching (preferred over detection-time licenses).
  • Content digests as component hashes (CycloneDX hashes, SPDX checksums).
  • CPEs (CycloneDX cpe, SPDX SECURITY/cpe23Type external references).
  • Vulnerabilities — CycloneDX as a first-class vulnerabilities array (ratings, CWEs, advisories, affects); SPDX as SECURITY/advisory external references.
  • End-of-life status (CycloneDX bomly:eol* properties, SPDX package comment).

Reachability annotations and other Bomly-specific metadata are emitted in the JSON output (--json or --format json), not in the standard SBOM formats. See Output formats.

Format conversion

To convert between formats, run a scan and emit both in one pass:

bomly scan --sbom --path ./in.spdx.json --format cyclonedx > out.cdx.json

Bomly does not advertise a one-shot convert command — the scan pipeline is the conversion path.

See also