Using Maven <dependencyManagement> to Keep Versions Consistent Across Multi‑Module Builds
Learn how to centralize dependency versions in a parent POM with <dependencyManagement>, see a concrete example, and understand its limits.
10 Sept 2026, 22:29 UTC

The problem: version drift in a reactor build
When a project is split into several modules, each module often declares its own dependencies. Over time, different modules may start using different versions of the same library, leading to confusing test failures, duplicate classes in the final artifact, or painful upgrade efforts.
Thesis: centralize version control with <dependencyManagement>
Maven’s <dependencyManagement> section in a parent POM lets you declare a version once. Every child module that declares the same groupId:artifactId automatically inherits that version unless it explicitly overrides it. This works for both direct and transitive dependencies, giving you a single source of truth for the whole reactor.
How it works
- The parent POM contains a
<dependencyManagement>block. - When Maven builds a child module, it merges the child’s
<dependencies>with the parent’s<dependencyManagement>. - If the child does not specify a version, the managed version is used; if it does, the child’s version wins.
- The resulting effective POM shows the resolved version, which you can inspect with
mvn help:effective-pom.
Worked example
Imagine a parent POM (pom.xml) that wants to standardize on Apache Commons Lang 3.15.0 for all modules.
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>parent</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.15.0</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
A child module only needs to declare the dependency without a version:
<project>
<parent>
<groupId>com.example</groupId>
<artifactId>parent</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>service-api</artifactId>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
</dependencies>
</project>
To verify that the managed version is applied, run:
mvn help:effective-pom -pl service-api
The output will contain a <dependency> entry for commons-lang3 with <version>3.15.0</version>. You can also check the resolved tree:
mvn dependency:tree -pl service-api
The tree should show commons-lang3:3.15.0 under the module’s dependencies.
Trade‑offs and limitations
- Plugin versions are not managed – you need a separate
<pluginManagement>block for plugins. - Explicit overrides win – if a child module declares a different version, it overrides the managed value, which can re‑introduce conflicts.
- Only versions are controlled – unwanted transitive dependencies still appear; use
<exclusions>or the Maven Enforcer Plugin to ban them.
Actionable steps to adopt
- Add a
<dependencyManagement>section to your parent POM with the libraries you want to standardize. - Run
mvn help:effective-pomon a few modules to confirm the versions are injected as expected. - Use
mvn dependency:treeto spot any version mismatches; treat mismatches as failures in CI (e.g., with the Enforcer Plugin’srequireUpperBoundDepsrule). - Document the policy: teams should avoid declaring versions in child modules unless a deliberate override is needed, and such overrides should be reviewed.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.