An SPDX SBOM records dependencies as relationship lines in the form A, a relationship type, B. DEPENDS_ON says A needs B to build or run, CONTAINS says B sits inside A, and DESCRIBES links the document to its main subject. Without these lines you have a list, not a graph.
The syntax
Each relationship is three parts: a left identifier, a type keyword, and a right target. Either side can point to another document with a DocumentRef prefix. The right side can also be NONE, meaning no related elements exist, or NOASSERTION, meaning the author makes no claim.
Example from the specification: SPDXRef-grep CONTAINS SPDXRef-make.
The types you will meet most
| Type | Plain meaning |
|---|---|
| DESCRIBES, DESCRIBED_BY | Ties the document to what it documents |
| DEPENDS_ON | The element needs another to build or run |
| CONTAINS, CONTAINED_BY | One element is nested in another, like a file in an archive |
| BUILD_DEPENDENCY_OF | A dependency in build scope, such as Maven compile |
| DEV_DEPENDENCY_OF | A dependency used only in development |
| GENERATED_FROM | A binary built from a source file, for example |
The scope types matter for noise. A DEV_DEPENDENCY_OF entry tells a reader a package never reaches production, which is a reason to deprioritize its advisories.
Read one in four steps
- Find the DESCRIBES line. It names the root, the thing the SBOM is about. The specification makes it mandatory when more than one package or set of files is present.
- List every DEPENDS_ON line from the root. Those are your direct dependencies.
- Follow each target's own lines to reach transitive ones.
- Check scope types to separate build only and dev only packages from runtime ones.
What breaks the graph
- A package listed with no relationship at all. A tool cannot tell if it is a dependency or a leftover.
- A missing DESCRIBES line in a multi package file, so the root is unclear.
- Using CONTAINS where DEPENDS_ON is meant. Containment is about packaging, dependency is about need.
- Treating NOASSERTION as a statement of no dependencies. It means the author did not say.
A small example helps. Suppose a service describes itself, depends on a web framework, and the framework depends on a parser. The file needs a DESCRIBES line for the service, a DEPENDS_ON line from the service to the framework, and a DEPENDS_ON line from the framework to the parser. Remove the middle line and the parser looks like an orphan, even though it ships. Scanners then report it without a parent, and nobody can tell which upgrade would remove it.
Quick check
What is the difference between DEPENDS_ON and CONTAINS?
DEPENDS_ON is about needing another element to build or run. CONTAINS is about one element being nested inside another.
Does NONE mean the same as NOASSERTION?
No. NONE says there are no related elements. NOASSERTION says the author makes no claim either way.
Safeguard's SBOM and dependency scanning builds a dependency graph from SBOM data, and a free scan is available at gold.safeguard.sh/scan.
Sources
Last reviewed: 19 October 2026.