skip to content

How do you import a BOM in Maven, and what does it accomplish?

level: middleimportance: must knowfreq 70%

answer

  1. type=pom + scope=import
  2. BOM = only dependencyManagement
  3. frees the single parent slot
  4. import many BOMs
  5. local pin / first-import wins

basics

~20 s

A BOM (Bill of Materials) is a POM that only declares versions in its <dependencyManagement>. You import it by adding it inside your own <dependencyManagement> with <type>pom</type> and <scope>import</scope>. Then you use its libraries without specifying versions.

solid answer

~40 s

A BOM is a special POM whose only job is to publish a curated, mutually-compatible set of versions in its <dependencyManagement>. You consume it via import scope: inside YOUR <dependencyManagement>, add the BOM artifact with <type>pom</type> and <scope>import</scope>. Maven inlines all of the BOM's managed entries into yours. Now your modules list libraries in <dependencies> without versions and get the BOM-blessed ones. This is how spring-boot-dependencies, jackson-bom, etc. work. Import scope is specifically needed because a BOM is a POM, not a jar, and because Maven inheritance only allows a single parent — import lets you pull in many BOMs without consuming the parent slot. Your own <dependencyManagement> entries override imported ones, and import order matters (first-declared wins on conflicts).

code

xml · 11 lines
xml
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-dependencies</artifactId>
      <version>3.3.1</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

go deeper

for a junior

Knows a BOM centralizes versions and is imported with type=pom and scope=import.

for a middle

Can write the import block and explain why import frees the parent slot and lets you import many BOMs.

for a senior

Understands override/ordering rules and chooses import vs parent-BOM deliberately.

for a principal

Publishes an internal org BOM to standardize versions across teams and governs its upgrade cadence.

## What a BOM is **BOM = Bill of Materials.** It is a published `pom.xml` (packaging `pom`) that contains *only* a `<dependencyManagement>` block listing a coherent set of artifact versions that are known to work together. Examples: `spring-boot-dependencies`, `jackson-bom`, `junit-bom`, `testcontainers-bom`. A BOM ships no code — just version policy. ## Why 'import' scope exists Maven inheritance gives each POM exactly one `<parent>`. If your aggregator parent is already something else, you cannot also 'extend' a BOM. **Import scope** solves this: it copies a BOM's managed dependencies into your own `<dependencyManagement>` without using the parent slot, and you can import *several* BOMs. ## How to import ```xml <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>3.3.1</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <!-- version supplied by the imported BOM --> </dependency> </dependencies> ``` The two required markers are **`<type>pom</type>`** (it's a POM, not a jar) and **`<scope>import</scope>`**. ## Resolution rules to know - **Import is resolved at the point of declaration**: the BOM's entries are flattened into your dependencyManagement as if you'd typed them there. - **Locally-declared management wins**: if you also pin a version directly in your <dependencyManagement>, it overrides the imported BOM. - **Order matters across multiple BOMs**: when two imported BOMs manage the same artifact, the *first declared* import wins (nearest-first within your management list). - Import scope is valid **only inside <dependencyManagement>**; using `scope=import` in a normal <dependencies> entry is meaningless. ## Alternative: parent BOM You can also make the BOM your `<parent>` (Spring Boot's classic pattern), which auto-applies its dependencyManagement plus plugin management. Import scope is the choice when you can't or don't want to give up the parent slot.

  • Why use import scope instead of just making the BOM your parent?
    A POM has only one parent. Import scope lets you pull in many BOMs and keep your own aggregator parent.
  • If two imported BOMs manage the same artifact at different versions, which wins?
    The first-declared import wins. Or you can override explicitly by pinning the version directly in your own dependencyManagement.
  • Can you put scope=import on a normal <dependencies> entry?
    No — import scope is only meaningful inside <dependencyManagement> on a <type>pom</type> artifact.

saying these in an interview costs you the question

  • Forgetting <type>pom</type> (defaults to jar, so the import fails to resolve as a BOM).
  • Thinking import scope works inside <dependencies>.
  • Believing a BOM adds dependencies to the classpath — it only manages versions.

context