Centralizing Dependency Versions in Maven Multi‑Module Projects with <dependencyManagement>
Centralize dependency versions in Maven multi‑module projects with <dependencyManagement>. Learn how to declare a single source of truth, verify inheritance, and avoid common pitfalls.
29 Jun 2026, 21:27 UTC

Why Matters
In a multi‑module Maven build, each module can declare the same library but with different versions. That leads to the classic "jar hell" where two modules ship different copies of the same JAR, causing runtime conflicts. <dependencyManagement> lets a parent POM define a single source of truth for dependency versions, while child modules simply reference the dependency without specifying a version.
How It Works
The <dependencyManagement> element lives in the parent POM. It lists dependencies with groupId, artifactId, and version (and optionally scope, exclusions, etc.). When a child module declares the same dependency in its <dependencies> section, Maven pulls the version from the parent automatically. The child’s declaration can omit the <version> tag entirely; if it includes a different version, that child‑specific override will win.
Key points:
- Only the parent POM’s
<dependencyManagement>defines the version. The child must still list the dependency in its own<dependencies>block. - Inheritance is transitive: a grandchild module inherits the same version unless it overrides it.
- The mechanism separates "what the project needs" (the dependency declaration) from "which exact artifact to use" (the version).
Practical Example
Below is a minimal parent/child structure that demonstrates the feature.
// Parent POM (pom.xml in the root directory)
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>parent-project</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>module-a</module>
<module>module-b</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
// Child module (module-a/pom.xml)
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>parent-project</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>module-a</artifactId>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<!-- No tag – it inherits 3.12.0 from the parent -->
</dependency>
</dependencies>
</project>
To verify the inheritance, run from the root directory:
mvn -pl module-a dependency:tree
The output should show org.apache.commons:commons-lang3:jar:3.12.0 on the tree, confirming that the child module picked up the version from the parent. If you change the parent’s version to 3.13.0 and re‑run the command, module-a will automatically use the new version without any changes to its own POM.
Common Pitfalls and Limits
- Missing
<dependencies>in the child: Declaring a dependency only in<dependencyManagement>does not add it to the classpath. The child must still list the dependency in its own<dependencies>section. - Overriding in a child: If a child declares a different version, that override takes precedence. Auditing is required to avoid accidental divergence.
- Single‑module projects: For a project with only one module, using
<dependencyManagement>adds unnecessary indirection. It’s fine, but the benefit is minimal. - Transitive dependencies:
<dependencyManagement>only controls the direct dependencies you declare. Transitive dependencies still follow the nearest‑definition rule unless overridden. - Version ranges: Maven does not support version ranges in
<dependencyManagement>for the same reason it doesn’t in<dependencies>. Use explicit versions.
When to Use BOMs (Bill of Materials)
Sometimes you want to import a curated set of dependency versions from another project. Maven’s import scope lets you do that:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>3.2.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
Place this inside <dependencyManagement> of your parent POM. All downstream modules inherit the versions for Spring Boot libraries without needing to list each one separately.
Summary
Using <dependencyManagement> in a parent POM centralizes version control for multi‑module builds, reduces duplication, and prevents classpath conflicts. The trick is to remember that the parent only supplies the version; each child still declares the dependency itself. When used correctly, this pattern scales cleanly as projects grow.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.