Multi-module projects and parent POMs

Maven · Practical · 12 min

Most real Maven codebases are multi-module; inheritance and the reactor are what make them manageable.

A multi-module build has a root POM with <packaging>pom</packaging> that lists <modules> (folder names). Each module has its own POM and usually declares the root as its <parent>. Two separate mechanisms are at work:

  • Aggregation (<modules>): the reactor builds all listed modules, ordering them by their inter-dependencies.
  • Inheritance (<parent>): a child POM inherits properties, dependencyManagement, pluginManagement, repositories and plugins from its parent. The child needs only artifactId (groupId and version are inherited). <relativePath> points to the parent POM on disk; the default ../pom.xml works for the usual layout.

Modules depend on each other with normal <dependency> elements using ${project.version} for the version. The reactor resolves these from the modules being built (in Maven 3, the artifact must have been packaged in the same run, which is why mvn install was the traditional command; Maven 4 handles this better).

Useful reactor flags:

  • -pl api,core build selected modules; -am also build their dependencies; -amd also build dependents.
  • -rf :api resume from a module after a failure.
  • -T 4 (or -T 1C) builds independent modules in parallel.

Keep versions in sync across modules with the flatten or versions plugins, or with ${revision} CI-friendly versions (<version>${revision}</version> and -Drevision=1.2.0).

Run mvn help:effective-pom -pl api to see what a module really inherits.

Example

<!-- pom.xml (root / parent) -->
<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.acme</groupId>
  <artifactId>shop-parent</artifactId>
  <version>${revision}</version>
  <packaging>pom</packaging>
  <properties>
    <revision>1.2.0-SNAPSHOT</revision>
    <maven.compiler.release>21</maven.compiler.release>
  </properties>
  <modules>
    <module>core</module>
    <module>api</module>
  </modules>
</project>
<!-- api/pom.xml -->
<project>
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.acme</groupId>
    <artifactId>shop-parent</artifactId>
    <version>${revision}</version>
  </parent>
  <artifactId>api</artifactId>
  <dependencies>
    <dependency>
      <groupId>com.acme</groupId>
      <artifactId>core</artifactId>
      <version>${project.version}</version>
    </dependency>
  </dependencies>
</project>
<!-- mvn -pl api -am package     mvn -T 1C verify     mvn -rf :api install -->

Remember

  • modules aggregate (reactor); parent inherits (configuration)
  • Children inherit groupId, version, management sections and plugins
  • -pl, -am, -amd and -rf select what to build; -T parallelizes
  • Use ${revision} or the flatten plugin for CI-friendly versions

Watch out for

  • Changing the parent version and forgetting to update the <parent> block in every module.

Check yourself

  1. What does mvn -pl api -am package do?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: maven.apache.org/guides/mini/guide-multiple-modules.html