# SBOM Examples: Real CycloneDX and SPDX Files, Annotated

> Real SBOM examples in CycloneDX and SPDX, annotated field by field, with the same software shown in both formats. Includes live SBOMs you can download and check against the NTIA minimum elements.

- **Updated:** 2026-08-31

Most SBOM articles describe the idea and stop. This page shows the files. Every example below is either taken from a real, published SBOM you can download yourself, or is a minimal document reduced to the fields that matter, and each one is annotated so you can see what each field is for.

If you want the concept first, start with [what an SBOM is](https://sbomify.com/what-is-sbom/) and come back.

## The shape of an SBOM

Whatever the format, an SBOM has two halves:

1. **A header about the SBOM itself.** Who produced it, with which tool, when, and what software it describes. This is the part people forget, and it is the part auditors ask about first.
2. **A list of components.** Each with a name, a version, a supplier and, ideally, a unique identifier and a license.

The formats disagree only on vocabulary. CycloneDX calls them `components`; SPDX calls them `packages`.

## A minimal CycloneDX example

This is close to the smallest document that is still a useful SBOM. CycloneDX will validate with only `bomFormat`, `specVersion` and `version`, but a document without a timestamp, a producer or a subject tells a consumer nothing.

```json
{
  "bomFormat": "CycloneDX",
  "specVersion": "1.6",
  "serialNumber": "urn:uuid:6a6df004-b6c9-4f38-9b5a-1f0c2f1c4d3e",
  "version": 1,
  "metadata": {
    "timestamp": "2026-07-30T13:45:53Z",
    "tools": [
      {
        "vendor": "sbomify, ltd",
        "name": "sbomify",
        "version": "26.7.1"
      }
    ],
    "component": {
      "type": "application",
      "name": "sbomify",
      "version": "26.7.1"
    }
  },
  "components": []
}
```

Reading it field by field:

| Field                      | What it is for                                                                                                             |
| -------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `bomFormat`, `specVersion` | Identifies the document as CycloneDX and pins the schema version. A consumer needs both before it can parse anything else. |
| `serialNumber`             | A UUID URN unique to this document. Together with `version` it lets you tell a re-issued SBOM from a different one.        |
| `version`                  | The revision of _this_ SBOM, not of the software. Bump it when you republish an SBOM for the same build.                   |
| `metadata.timestamp`       | When the SBOM was assembled. One of the NTIA minimum elements.                                                             |
| `metadata.tools`           | What produced the SBOM. The other half of the "author of SBOM data" element.                                               |
| `metadata.component`       | The subject: the thing this SBOM is _about_. Without it, a consumer has a list of parts and no idea what they add up to.   |
| `components`               | The inventory. Empty here; populated below.                                                                                |

## The same document in SPDX

SPDX describes the same facts with different names. This is the SPDX 2.3 equivalent of the header above.

```json
{
  "spdxVersion": "SPDX-2.3",
  "dataLicense": "CC0-1.0",
  "SPDXID": "SPDXRef-DOCUMENT",
  "name": "sbomify",
  "documentNamespace": "https://sbomify.com/spdxdocs/sbomify-26.7.1",
  "creationInfo": {
    "created": "2026-07-30T13:45:53Z",
    "creators": [
      "Organization: sbomify, ltd",
      "Tool: sbomify-26.7.1"
    ]
  },
  "packages": [],
  "relationships": []
}
```

The mapping is close to one-to-one:

| CycloneDX            | SPDX                    | Notes                                                                              |
| -------------------- | ----------------------- | ---------------------------------------------------------------------------------- |
| `specVersion`        | `spdxVersion`           | Schema version.                                                                    |
| `serialNumber`       | `documentNamespace`     | SPDX uses a URI rather than a UUID URN.                                            |
| `metadata.timestamp` | `creationInfo.created`  | Same field, different spelling.                                                    |
| `metadata.tools`     | `creationInfo.creators` | SPDX puts organisation and tool in one list, prefixed `Organization:` and `Tool:`. |
| `components`         | `packages`              | The inventory.                                                                     |
| implicit nesting     | `relationships`         | CycloneDX can nest components; SPDX always states relationships explicitly.        |

`dataLicense` is an SPDX quirk with no CycloneDX equivalent: it is the license of _the SBOM document itself_, and the spec requires `CC0-1.0`.

For the differences that go beyond naming, governance, license depth, native vulnerability support, and which compliance frameworks expect which, see our [comparison of the two formats](https://sbomify.com/2026/01/15/sbom-formats-cyclonedx-vs-spdx/).

## A real component entry

An empty `components` array is not much of an example. This entry is taken verbatim from an SBOM generated against the `alpine:3.18` container image, and it is what a well-formed component actually looks like:

```json
{
  "bom-ref": "pkg:apk/alpine/alpine-baselayout-data@3.4.3-r1?arch=x86_64&distro=3.18.12",
  "type": "library",
  "name": "alpine-baselayout-data",
  "version": "3.4.3-r1",
  "supplier": {
    "name": "Natanael Copa <ncopa@alpinelinux.org>"
  },
  "hashes": [
    {
      "alg": "SHA-1",
      "content": "602007ee374ed96f35e9bf39b1487d67c6afe027"
    }
  ],
  "licenses": [
    {
      "license": {
        "id": "GPL-2.0-only"
      }
    }
  ],
  "purl": "pkg:apk/alpine/alpine-baselayout-data@3.4.3-r1?arch=x86_64&distro=3.18.12"
}
```

Three things are worth pointing out.

**The `purl` is the identifier that matters.** A [Package URL](https://github.com/package-url/purl-spec) encodes ecosystem, namespace, name, version and qualifiers in one string, which is what makes automated vulnerability matching possible. `pkg:apk/alpine/...` says this is an Alpine `apk` package; a Python dependency would read `pkg:pypi/requests@2.32.3`. Name and version alone are ambiguous across ecosystems.

**The license is an SPDX identifier, not free text.** `GPL-2.0-only` is a value from the [SPDX license list](https://spdx.org/licenses/). Writing `"GPLv2"` instead is the single most common way to make a license field useless to automation.

**`supplier` is a minimum element and is usually missing.** Most generators leave it out because the upstream package metadata does not carry it. If you are producing SBOMs for customers, this is the field to check first.

## Checking an example against the minimum elements

A file that validates against the schema is not automatically a _good_ SBOM. The US baseline is the [CISA 2026 minimum elements](https://sbomify.com/compliance/cisa-minimum-elements/), published on 29 July 2026, which updates and replaces the [NTIA 2021 minimum elements](https://sbomify.com/compliance/ntia-minimum-elements/).

Against that baseline, the component above scores:

| Minimum element          | In the example?                                       |
| ------------------------ | ----------------------------------------------------- |
| Supplier name            | Yes, `supplier.name`                                  |
| Component name           | Yes, `name`                                           |
| Version                  | Yes, `version`                                        |
| Other unique identifiers | Yes, `purl`                                           |
| Dependency relationship  | Only at document level, via nesting or `dependencies` |
| Author of SBOM data      | In the header, `metadata.tools`                       |
| Timestamp                | In the header, `metadata.timestamp`                   |

Note that two of the seven elements live in the header, not in the component. An SBOM that is nothing but a component list cannot meet the baseline no matter how good the entries are.

## Live SBOMs you can download

Hand-written snippets are tidy in a way that real SBOMs are not. sbomify publishes the SBOMs for its own product, in both formats, on its [public Trust Center](https://trust.sbomify.com/product/sbomify/), including the product-level SBOM that references the SBOMs of each underlying component rather than flattening everything into one list.

Two other sources worth knowing, both from the projects that maintain the specifications themselves:

- The [CycloneDX BOM examples repository](https://github.com/CycloneDX/bom-examples), maintained by the OWASP CycloneDX project, covering SBOM, VEX, VDR and CBOM documents.
- The [SPDX specification](https://spdx.dev/use/specifications/), maintained by the Linux Foundation, whose annexes include worked examples in each supported serialisation.

For background on why these documents are being asked for, [CISA's SBOM resources](https://www.cisa.gov/sbom) and the [OpenSSF](https://openssf.org/) guidance are the primary references, and [ENISA](https://www.enisa.europa.eu/) covers the European position.

## Generating your own

Reading examples only gets you so far. Every ecosystem has a different route from lockfile to SBOM, and our [language guides](https://sbomify.com/guides/) cover them one by one, from `uv.lock` and `Cargo.lock` through to container images.

The short version: generate from a lockfile where you can, enrich the result so the supplier and license fields are actually populated, and publish it somewhere your customers can find it without emailing you.

**Ready to publish your own SBOMs?** [Start free](https://app.sbomify.com) or [Book a demo](https://app.sbomify.com/enterprise-contact/).

---

From sbomify: https://sbomify.com/sbom-examples/
