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 onlyartifactId(groupId and version are inherited).<relativePath>points to the parent POM on disk; the default../pom.xmlworks 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,corebuild selected modules;-amalso build their dependencies;-amdalso build dependents.-rf :apiresume 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.