What is a Maven BOM, and how do you author one?
answer
- packaging=pom, no code
- dependencyManagement = version catalog
- import scope + type pom
- consumer omits version
- spring-boot-dependencies
basics
~10 sA BOM (Bill of Materials) is a POM-packaged artifact whose only job is a <dependencyManagement> block listing curated versions. Consumers import it so they can add those dependencies without specifying versions.
solid answer
~30 sA BOM is an artifact with `<packaging>pom</packaging>` that contains a `<dependencyManagement>` section pinning versions (and sometimes scopes/exclusions) for a set of related libraries. It ships no code — it is a published version catalog. You author it as a standalone module (its own groupId/artifactId/version) declaring managed dependencies. Downstream projects pull it in with `<scope>import</scope>` and `<type>pom</type>` inside their own `<dependencyManagement>`, then declare those dependencies version-free. This centralizes version decisions, guarantees compatible sets (e.g. Spring Boot, Jackson modules), and lets you bump one BOM version to upgrade everything coherently. Well-known examples: spring-boot-dependencies, jackson-bom.
code
xml · 15 lines<project>
<groupId>com.acme</groupId>
<artifactId>acme-bom</artifactId>
<version>1.4.0</version>
<packaging>pom</packaging>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.acme</groupId>
<artifactId>acme-core</artifactId>
<version>1.4.0</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>go deeper
Know a BOM is a versions-only POM and consumers omit the version.
Author one with packaging=pom + dependencyManagement; know import scope mechanics.
Curate compatible sets, version the BOM independently, document upgrade policy.
Govern org-wide version policy via BOMs; decide BOM granularity and ownership.
## What a BOM is A **BOM (Bill of Materials)** is a special Maven artifact whose sole purpose is to declare a curated, internally-consistent set of dependency **versions**. It contains no Java code and produces no JAR — it is published as a POM file only. Think of it as a published, versioned price-list of "if you use library X, use exactly this version." ## How it is built Two things define a BOM: 1. `<packaging>pom</packaging>` — tells Maven this artifact is just a POM, no compiled output. 2. A `<dependencyManagement>` block — this section **declares** versions but does **not** add dependencies to anyone's classpath. It only takes effect when a dependency with the same groupId+artifactId is actually declared. ```xml <project> <groupId>com.acme</groupId> <artifactId>acme-bom</artifactId> <version>1.4.0</version> <packaging>pom</packaging> <dependencyManagement> <dependencies> <dependency> <groupId>com.acme</groupId> <artifactId>acme-core</artifactId> <version>1.4.0</version> </dependency> <dependency> <groupId>com.acme</groupId> <artifactId>acme-web</artifactId> <version>1.4.0</version> </dependency> </dependencies> </dependencyManagement> </project> ``` ## How consumers use it A downstream project imports the BOM **inside its own `<dependencyManagement>`** using `<scope>import</scope>` and `<type>pom</type>`: ```xml <dependencyManagement> <dependencies> <dependency> <groupId>com.acme</groupId> <artifactId>acme-bom</artifactId> <version>1.4.0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> ``` Then the consumer declares the actual dependency **without a `<version>`** — the BOM supplies it: ```xml <dependencies> <dependency> <groupId>com.acme</groupId> <artifactId>acme-core</artifactId> </dependency> </dependencies> ``` ## Why it matters - **Single source of version truth** — bump the BOM version once, every consumer upgrades coherently. - **Compatibility guarantee** — the publisher has tested that all listed versions work together (e.g. all Jackson modules at the same minor). - **Decouples version policy from usage** — teams declare *what* they need, not *which version*. Real-world BOMs: `spring-boot-dependencies`, `spring-cloud-dependencies`, `jackson-bom`, `junit-bom`.
- Does <dependencyManagement> add a dependency to the classpath?No. It only declares versions/scopes/exclusions. The dependency must still be declared in <dependencies> for it to be on the classpath.
- What packaging must a BOM use?pom — it ships only a POM file, no JAR.
A BOM is like a restaurant's tasting menu: it lists exact dishes that pair well together. You don't pick portions — you just say 'I'll have the menu' and everything is pre-matched.
saying these in an interview costs you the question
- Saying a BOM puts dependencies on the classpath (it only manages versions).
- Confusing a BOM with a fat/uber JAR.
- Thinking the BOM must be a parent of the consumer.