A Maven BOM is a special POM that lists recommended versions so related libraries stay in sync. An SBOM is a separate document that records the components actually inside a build. The first controls what Maven resolves. The second describes what resolved. Java teams usually need both, and confusing them causes real gaps.
Two things that share three letters
"BOM" in the Maven world means bill of materials POM. The Maven documentation describes the pattern: the root project defines the versions of all artifacts in a library, and other projects import that POM into their dependencyManagement section so versions stay aligned.
An SBOM, in contrast, is a software bill of materials. Formats such as CycloneDX describe the components in a product, their versions and their relationships. It is a record, not an instruction to the build tool.
| Maven BOM | SBOM | |
|---|---|---|
| Purpose | Align versions across modules | Inventory what a build contains |
| Who reads it | Maven, at resolution time | People, scanners, customers, auditors |
| Format | A POM with packaging pom | CycloneDX or SPDX, JSON or XML |
| Lists transitive dependencies | Only the ones it manages | All that were resolved |
| Changes build output | Yes, it can change versions | No |
Why the difference matters for security
A BOM can reduce risk because one place sets the version. If a library family ships a fix, bumping the BOM version moves every module together. But a BOM only lists what it chooses to manage. Anything it does not mention still resolves by Maven's normal rules.
An SBOM answers a different question: when an advisory lands, which of our builds contain the affected component? You cannot answer that from a BOM, because a BOM never saw the full resolved tree.
Gradle has an equivalent idea. Its documentation says custom platforms can be published as Maven BOMs, and that consumers use the platform keyword to pull recommended versions from one. Same rule applies: it controls versions, it is not an inventory.
How to use both
- Import a BOM for each large library family you use, in dependencyManagement with import scope, so versions move together.
- Generate an SBOM from every build that ships. The CycloneDX Maven plugin, for example, creates an SBOM with the aggregate of direct and transitive dependencies.
- Store the SBOM next to the release artifact so you can search it later.
- When you bump a BOM, regenerate and compare the SBOM so you can see what really changed.
A short sketch of the import step:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>example-bom</artifactId>
<version>1.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Common mistakes
Treating the BOM as proof of what shipped is the big one. A second is forgetting that a vendor BOM might pin an older version of a transitive library than the one you now need. You can still override it in your own dependencyManagement, which takes effect for your project.
Try it yourself
Click through it at your own pace, or open it full screen. Look at how direct and transitive components are listed together, which is the view a BOM POM cannot give you.
Safeguard produces SBOMs and runs dependency scanning on Java projects, and reachability analysis helps you decide which findings in that inventory matter first. You can run a free scan at gold.safeguard.sh/scan.
Quick check
Can a Maven BOM replace an SBOM?
No. A BOM sets versions for the build. An SBOM records what the build actually contained. Customers and auditors who ask for an SBOM want the second document.
Does importing a BOM make my dependencies safer?
It keeps related versions consistent, which helps when you need to upgrade a family together. It does not check for vulnerabilities, so you still need scanning.
Sources
- Introduction to the Dependency Mechanism, Apache Maven
- Platforms, Gradle documentation
- CycloneDX Maven plugin
Last reviewed: 19 October 2026.