(If you're working with Maven 3, please refer to the Maven 3 edition of this guide)
As seen in the introduction to the POM, Maven supports project aggregation in addition to project inheritance. This section outlines how Maven processes projects with multiple subprojects, and how you can work with them more effectively.
The mechanism in Maven that handles projects with multiple subprojects is referred to as the reactor. This part of the Maven core does the following:
Subproject collection starts from one aggregator project. That project defines the subprojects of which it consists using the <subproject> element. This is a recursive process, so aggregators can have child subprojects which are aggregators themselves.
For this process to work, it does not matter which POM you start with. Maven attempts to find the root of a multi-project setup, by traversing upwards in the directory structure until it either finds a POM with a .mvn sibling directory or a POM with the root attribute set to true. This allows Maven to resolve dependencies on subprojects from the same project, regardless of the location of the starting POM. When Maven fails to find the root, it assumes that the starting POM is the root. For consistent behaviour, create a .mvn directory in the root directory of the project or set the root attribute in the POM of the root project to true.
There are two ways to point at a starting POM. By default, Maven reads the pom.xml file in the working directory. Using the file parameter (--file or -f), you can point to another POM.
Because subprojects within a multi-project build can depend on each other, it is important that the reactor sorts all the projects in a way that guarantees each project is built before it is required.
The following relationships are honoured when sorting projects:
<subprojects> element (if no other rule applies)Note that only “instantiated” references are used - dependencyManagement and pluginManagement elements do not cause a change to the reactor sort order.
By default, Maven builds all subprojects it has collected. However, you can select a subset of these subprojects to build using command line flags. These flags come in three categories:
This section ends with how these flags relate to each other.
Using --projects you can specify which subprojects to build. You can do this by specifying a comma-delimited list of project selectors. A project selector is a string that is composed of the groupId:artifactId, only :artifactId or the relative path to a subproject.
A subproject can be selected (default), or excluded from the build. You exclude a subproject by prefixing the selector with a ! or -. To explicitly select a subproject, prefix it with a +.
When a selector does not resolve to an existing subproject, Maven fails the build. You can prevent this by adding the ? prefix. This prefix should always go after the other prefixes.
Subprojects inside a project can have two types of relationships: parent/child and dependency/dependent.
When selecting a parent (aggregator), Maven automatically selects the child subprojects as well. Similarly, Maven excludes child subprojects of an excluded parent (aggregator). To prevent this recursive behaviour, combine --projects with --non-recursive.
Maven knows about the dependencies between subprojects inside the multi-project setup. Using --also-make, Maven includes all dependencies of the selected projects in the build. Similarly, --also-make-dependents lets Maven include all subprojects which depend on the selected projects.
There are several ways to customize how the reactor deals with failures.
--fail-at-end fails the build after building as many subprojects as possible. In this case, subprojects that do not depend on a failed subproject will still be built.--fail-fast, in contrast, fails the build as soon as one subproject has failed. This is the default behaviour.--fail-never ignores build failures.When a build has failed, and you want to start it again, you can skip building the subprojects that were previously built successfully using --resume (or -r). To resume a build from a specific subproject, you can use --resume-from <selector>.
As said, Maven includes all subprojects in the reactor, even when the starting POM is not the root of the project. The reactor then selects which subprojects to build using the following steps:
--projects and, if --resume is given, the remaining subprojects of a previously failed build.--resume-from.--projects (using the ! or - prefixes).Each of the steps 1, 2 and 3 honor the --also-make and --also-make-dependents flags, if they are given.
No special configuration is required to take advantage of the reactor, however it is possible to customize its behavior.
The following command line switches are available:
| Long | Short | Summary | Details |
|---|---|---|---|
--file | -f | Selects an alternative POM file or directory containing a POM file. | Collecting subprojects |
--non-recursive | -N | Ignores any child subprojects that may be present in the starting POM. When combined with -pl, ignores the children of selected subprojects. | Collecting subprojects and Relationships between subprojects |
--projects | -pl | Specifies the subprojects to include or exclude from a build. | Inclusion and exclusion |
--also-make | -am | Builds the specified subprojects, and any of their dependencies in the reactor. | Relationships between subprojects |
--also-make-dependents | -amd | Builds the specified subprojects, and any that depend on them. | Relationships between subprojects |
--resume-from | -rf | Resumes a reactor from the specified project (e.g. when it fails in the middle). | Dealing with failures |
--resume | -r | Resumes a reactor from the subproject where the previous build failed. | Dealing with failures |
--fail-fast | -ff | Stops the overall build immediately whenever a subproject build fails. This is the default behavior. | Dealing with failures |
--fail-at-end | -fae | Continues the rest of the reactor if a particular subproject build fails and report all failed subprojects at the end instead. | Dealing with failures |
--fail-never | -fn | Never fails the build, regardless of the project result. | Dealing with failures |
The table below illustrates multiple scenarios which have changed between Maven 3 and 4. They assume a project structure as depicted above.
| Scenario | Outcome (in order) | Maven 3 | Maven 4 |
|---|---|---|---|
| Build an aggregator and its children | subproject-c, subproject-c-1, subproject-c-2 | mvn compile -pl subproject-c, subproject-c-1, subproject-c-2 | mvn compile -pl subproject-c |
| Build an aggregator and ignore its children | subproject-c, subproject-c-1, subproject-c-2 | mvn compile -pl subproject-c | mvn compile -pl subproject-c -N |
| Also make dependencies outside of current scope | parent, subproject-a, subproject-b, subproject-c, subproject-c-2 | N/A | cd subproject-c/subproject-c-2 && mvn compile -am |
| Also make dependents outside of current scope | subproject-a, subproject-b, subproject-c-2 | N/A | cd subproject-a && mvn compile -amd |
| Resuming from a subproject and build all dependencies | parent, subproject-a, subproject-b, subproject-c, subproject-c-2 | N/A | mvn compile -rf :subproject-c-2 -am or mvn compile -r -am |
| Run specific goal on one subproject with dependencies from project | subproject-c-2 | mvn install && mvn jetty:run -f subproject-c/subproject-c-2 | mvn compile && mvn jetty:run -f subproject-c/subproject-c-2 |