skip to content

Authoring a BOM

Publishing your own BOM — a pom-packaged artifact whose dependencyManagement downstream projects import — and how it differs from a parent POM. Asked of anyone who has maintained a library that ships several modules.

on this pageshow

explore

questions

6

In a multi-module project, how do you keep dependency versions consistent across modules?

level: middleimportance: must knowfreq 65%

answer

  1. versions in parent dependencyManagement
  2. version properties ${x.version}
  3. children omit version
  4. ${project.version}/${revision} for inter-module
  5. import external BOMs in parent

basics

~10 s

Put a <dependencyManagement> block (and version properties) in the shared parent POM. Child modules declare dependencies without versions, so every module uses the parent's pinned version.

solid answer

~30 s

Centralize versions in the reactor's parent POM using `<dependencyManagement>` plus `<properties>` for version numbers (e.g. `${jackson.version}`). Child modules inherit this and declare dependencies without a `<version>`, so a single change in the parent propagates everywhere — no drift. For inter-module references, keep `<version>${project.version}` aligned via a shared property or revision (CI-friendly versioning). If you also consume external version sets, import their BOMs inside the parent's `<dependencyManagement>`. This guarantees that, say, every module uses the same Jackson and the same internal module version, which is essential to avoid classpath conflicts when modules are assembled together.

code

xml · 11 lines
xml
<!-- parent -->
<properties><jackson.version>2.17.1</jackson.version></properties>
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>${jackson.version}</version>
    </dependency>
  </dependencies>
</dependencyManagement>

go deeper

for a junior

Children should omit versions and inherit them from the parent.

for a middle

Use dependencyManagement + properties; align inter-module versions with project.version.

for a senior

Adopt ${revision} CI-friendly versioning and import external BOMs centrally.

for a principal

Define org-wide version-governance conventions and publish a BOM as the contract.

## The drift problem In a multi-module (reactor) build, if each module declares its own versions, modules can diverge — module A on Jackson 2.16, module B on 2.17 — causing subtle runtime classpath conflicts when they're packaged together. Centralizing fixes this. ## Step 1 — version properties in the parent ```xml <properties> <jackson.version>2.17.1</jackson.version> <junit.version>5.10.2</junit.version> </properties> ``` ## Step 2 — dependencyManagement in the parent ```xml <dependencyManagement> <dependencies> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>${jackson.version}</version> </dependency> </dependencies> </dependencyManagement> ``` ## Step 3 — children declare version-free ```xml <dependencies> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </dependency> </dependencies> ``` The child inherits the managed version. Change `${jackson.version}` once and all modules move together. ## Inter-module versions For dependencies between your own modules, use `<version>${project.version}</version>` or the **CI-friendly `${revision}`** property so all modules share one version stamp: ```xml <version>${revision}</version> <properties> <revision>1.4.0-SNAPSHOT</revision> </properties> ``` Then `mvn -Drevision=1.4.0 deploy` versions the whole reactor at once. ## Pulling in external version sets Need Spring/Jackson curated sets too? Import their BOMs in the parent's `<dependencyManagement>` (scope=import, type=pom). All children inherit those managed versions automatically. ## Optionally publish your own BOM If downstream teams consume your modules, also publish a BOM so they pin your modules without adopting your parent. The parent governs your internal build; the BOM exports the version contract.

  • How do you keep inter-module dependency versions in sync?
    Use ${project.version} or the CI-friendly ${revision} property so every module shares one version stamp.
  • Where do you put external BOM imports for a reactor?
    In the parent POM's <dependencyManagement> with scope=import; children inherit the managed versions.

saying these in an interview costs you the question

  • Repeating versions in every child module (causes drift).
  • Hardcoding inter-module versions instead of ${project.version}/${revision}.
  • Putting versions in <dependencies> of the parent (forces them onto all children) when you only meant to manage them.

context

open as a page

What is a Maven BOM, and how do you author one?

level: middleimportance: must knowfreq 70%

basics

~10 s

A 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.

open as a page

Explain how <scope>import</scope> works and why it requires <type>pom</type>.

level: seniorimportance: must knowfreq 60%

basics

~10 s

Inside <dependencyManagement>, importing a BOM with scope=import and type=pom inlines that BOM's managed versions into your own dependencyManagement. type=pom is needed because the imported artifact is a POM, not a JAR.

open as a page

A teammate imported your BOM but their build can't find the classes. What likely went wrong?

level: juniorimportance: should knowfreq 40%

basics

~10 s

Importing a BOM only sets versions; it does not add anything to the classpath. They still need to declare the actual dependencies in <dependencies> (without a version) to get the classes.

open as a page

When would you author a BOM versus using a parent POM to share versions?

level: seniorimportance: should knowfreq 55%

basics

~20 s

Use a parent POM to share build config, plugins, and properties across YOUR modules (single parent only). Use a BOM when you want to publish version-only management that EXTERNAL consumers import, possibly alongside their own parent.

open as a page

How do you version and release a BOM, and what SNAPSHOT pitfalls should you watch for?

level: seniorimportance: should knowfreq 35%

basics

~10 s

Version the BOM independently and bump it whenever the curated versions change. A BOM ending in -SNAPSHOT pins consumers to mutable versions, so consumers should import released (non-SNAPSHOT) BOM versions for reproducible builds.

open as a page