An SPDXID is the unique label an SPDX document gives to each package, file or snippet so other parts of the document can refer to it. In SPDX 2.3 it must start with SPDXRef- followed by letters, numbers, dots and hyphens. Every element needs one, and relationships use them to point at each other.
What the spec says
In SPDX 2.3.1, the package SPDX identifier field is mandatory with exactly one value per package. The format is SPDXRef- followed by an idstring made of letters, numbers, a dot, and a hyphen. The stated intent is that there may be several versions of the same package inside one document, so each element must be uniquely referable and relationships can be stated clearly.
In tag-value form it looks like this.
PackageName: openssl
SPDXID: SPDXRef-Package-openssl-3.0.13
PackageVersion: 3.0.13
Identifiers are used in two places. The element declares its own SPDXID, and a relationship line names two of them.
Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-Package-app
Relationship: SPDXRef-Package-app DEPENDS_ON SPDXRef-Package-openssl-3.0.13
Local to the document, global with a namespace
An SPDXID is only guaranteed unique inside its document. For references from outside, the spec combines the document namespace and the identifier. In RDF form the URI follows the pattern namespace, then a hash sign, then the identifier. That is why the document namespace should itself be unique. Do not reuse one namespace across different SBOM files.
Choosing a naming convention
The spec does not tell you what string to use after the prefix, so decide a convention and apply it everywhere.
| Approach | Example | Trade-off |
|---|---|---|
| Counter | SPDXRef-1, SPDXRef-2 | Valid, but meaningless when read and unstable between runs |
| Name plus version | SPDXRef-Package-lodash-4.17.21 | Readable and stable, but must stay unique across duplicates |
| Name, version and ecosystem | SPDXRef-npm-lodash-4.17.21 | Avoids collisions between ecosystems with the same name |
Stable identifiers help diffing. If a generator renumbers elements on every run, two SBOMs for identical software will differ in every line even though nothing changed.
Mistakes to avoid
Using characters outside the allowed set. Slashes, colons, at signs and underscores are not in the list the spec gives. A purl pasted straight into an identifier will break it.
Forgetting the prefix. Package-openssl alone is not a valid SPDXID.
Duplicate identifiers. Two packages sharing one ID makes every relationship pointing at it ambiguous. This often happens when the same library appears at two versions and the generator keys on name only.
Hand edits after generation. If you rename an identifier, you must update every relationship that references it.
Safeguard can generate SBOMs and run dependency scanning across your repositories, so the fields discussed here are checked on real projects instead of by hand. You can try the free scan at gold.safeguard.sh/scan.
Try it yourself
Open the demo, click through the component list, and look at how each package is identified and what is missing.
Click through it at your own pace, or open it full screen.
Quick check
Can an SPDXID contain underscores or colons?
The 2.3.1 spec lists letters, numbers, dots and hyphens as the allowed characters after SPDXRef-, so avoid anything else.
Does the SPDXID need to be the same across SBOM runs?
The spec does not require it, but stable identifiers make diffs between runs much easier to read.
Sources
Last reviewed: 19 October 2026.