ZetCode

Maven command line

last modified November 8, 2026

In this article we cover the options of the mvn command. We show how to build selected modules of a multi-module project, handle failures, run parallel and offline builds, control the output, and store default options in the project. The examples use Maven 3.10 and Java 25.

The general form of the command is mvn [options] [goals and phases]. Options start with a dash, for instance -q or --quiet; most of them have a short and a long form. The mvn --help command lists all of them.

Phases and goals

A phase is a step of a lifecycle, such as compile or package. Running a phase runs all earlier phases of its lifecycle. Phases from different lifecycles can be combined: mvn clean package runs the clean lifecycle and then the default lifecycle up to package.

A goal is a single task of a plugin. It is written as prefix:goal, for example compiler:compile, or with full coordinates as groupId:artifactId:version:goal. The full form runs an exact plugin version without any configuration in the POM.

Both commands print the project version. The short form resolves the help prefix to the Maven Help Plugin and uses the version configured in the POM, or the latest release if there is none. The -N option is explained below.

$ mvn -q org.apache.maven.plugins:maven-help-plugin:3.5.2:evaluate \
  -Dexpression=project.version -DforceStdout -N
1.0.0
$ mvn -q help:evaluate -Dexpression=project.version -DforceStdout -N
1.0.0

The example project

Most options are useful in multi-module projects. Our shop project has four modules: common with a Money record, orders and reports, which both use common, and app, which uses orders. Each module except app has one unit test.

shop
├── common     Money
├── reports    Report      → common
├── orders     Order       → common
└── app        App         → orders

The POM files

The root POM is the parent and aggregator of the modules.

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>shop</artifactId>
    <version>1.0.0</version>
    <packaging>pom</packaging>

    <modules>
        <module>common</module>
        <module>reports</module>
        <module>orders</module>
        <module>app</module>
    </modules>

    <properties>
        <maven.compiler.release>25</maven.compiler.release>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.junit</groupId>
                <artifactId>junit-bom</artifactId>
                <version>6.1.3</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.16.0</version>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>3.6.1</version>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-jar-plugin</artifactId>
                    <version>3.5.1</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

The parent sets the Java release, adds JUnit 6 to all modules for testing, and pins the plugin versions.

orders/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.example</groupId>
        <artifactId>shop</artifactId>
        <version>1.0.0</version>
    </parent>

    <artifactId>orders</artifactId>

    <dependencies>
        <dependency>
            <groupId>com.example</groupId>
            <artifactId>common</artifactId>
            <version>${project.version}</version>
        </dependency>
    </dependencies>
</project>

The module POMs inherit from the root POM and declare dependencies on other modules. The other module POMs look the same.

reports/src/test/java/com/example/reports/ReportTest.java
package com.example.reports;

import com.example.common.Money;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

class ReportTest {

    @Test
    void formatsLine() {
        var expected = Boolean.getBoolean("broken") ? "broken" : "Sales        100.00 EUR";
        assertEquals(expected, Report.line("Sales", Money.of("100.00")));
    }
}

The test of the reports module fails on purpose when the broken system property is set. Surefire passes properties given on the Maven command line to the test JVM, so -Dbroken=true lets us simulate a failing module.

Building all modules

Without options, Maven builds all modules. The reactor sorts them so that every module comes after its dependencies; the order of reports and orders follows their order in the modules element.

$ mvn package
[INFO] Reactor Build Order:
[INFO] shop                                                               [pom]
[INFO] common                                                             [jar]
[INFO] reports                                                            [jar]
[INFO] orders                                                             [jar]
[INFO] app                                                                [jar]
[INFO] Reactor Summary for shop 1.0.0:
[INFO] shop ............................................... SUCCESS [  0.002 s]
[INFO] common ............................................. SUCCESS [  2.049 s]
[INFO] reports ............................................ SUCCESS [  0.680 s]
[INFO] orders ............................................. SUCCESS [  0.593 s]
[INFO] app ................................................ SUCCESS [  0.064 s]
[INFO] BUILD SUCCESS
...
$ java -cp app/target/app-1.0.0.jar:orders/target/orders-1.0.0.jar:common/target/common-1.0.0.jar \
  com.example.app.App
Order total: 24.50 EUR

Selecting modules with -pl

The -pl (--projects) option builds only the given modules. Modules are given by their directory, by :artifactId, or by groupId:artifactId, separated by commas. An exclamation mark, or a minus sign, excludes a module; in Bash the argument must be quoted, otherwise the shell interprets the exclamation mark.

The first two builds succeed, because all the needed modules are part of the build. The third fails: app needs orders and common, which are not in the build and not in the local repository. In Maven 3, a module outside the build is resolved like any other dependency.

$ mvn package -pl common,reports
[INFO] common ............................................. SUCCESS [  2.220 s]
[INFO] reports ............................................ SUCCESS [  0.680 s]
[INFO] BUILD SUCCESS
...
$ mvn package -pl '!reports'
[INFO] shop ............................................... SUCCESS [  0.002 s]
[INFO] common ............................................. SUCCESS [  1.746 s]
[INFO] orders ............................................. SUCCESS [  1.118 s]
[INFO] app ................................................ SUCCESS [  0.060 s]
[INFO] BUILD SUCCESS
...
$ mvn package -pl app
[ERROR] BUILD FAILURE
[ERROR] Failed to execute goal on project app: Could not resolve dependencies for project com.example:app:jar:1.0.0
[ERROR] dependency: com.example:orders:jar:1.0.0 (compile)
...

Also make with -am

The -am (--also-make) option adds the modules that the selected modules depend on. This is the usual way to build one module of a large project.

Maven built app together with orders and common, and the parent POM. The reports module was left out.

$ mvn package -pl :app -am
[INFO] shop ............................................... SUCCESS [  0.002 s]
[INFO] common ............................................. SUCCESS [  2.066 s]
[INFO] orders ............................................. SUCCESS [  0.719 s]
[INFO] app ................................................ SUCCESS [  0.068 s]
[INFO] BUILD SUCCESS
...

Also make dependents with -amd

The -amd (--also-make-dependents) option works in the other direction: it adds the modules that depend on the selected modules.

After a change in common, this command rebuilds and tests everything that may be affected by the change.

$ mvn package -pl common -amd
[INFO] common ............................................. SUCCESS [  2.092 s]
[INFO] reports ............................................ SUCCESS [  0.801 s]
[INFO] orders ............................................. SUCCESS [  0.609 s]
[INFO] app ................................................ SUCCESS [  0.088 s]
[INFO] BUILD SUCCESS
...

Failure handling

By default, Maven stops at the first module that fails; this is the -ff (--fail-fast) mode. The modules after it are skipped, even those that do not depend on the failed module.

The orders and app modules were skipped, although they do not depend on reports. Maven suggests the -rf option to resume the build.

$ mvn package -Dbroken=true
[INFO] Reactor Summary for shop 1.0.0:
[INFO] orders ............................................. SKIPPED
[INFO] app ................................................ SKIPPED
[INFO] shop ............................................... SUCCESS [  0.002 s]
[INFO] common ............................................. SUCCESS [  2.142 s]
[ERROR] reports ............................................ FAILURE [  0.680 s]
[ERROR] BUILD FAILURE
[ERROR] After correcting the problems, you can resume the build with the command
[ERROR]   mvn <args> -rf :reports

Fail at end and fail never

With -fae (--fail-at-end), Maven continues with the modules that do not depend on a failed module and reports the failure at the end. With -fn (--fail-never), it also reports failures, but the build always ends with exit status 0.

The -fae option is useful on CI servers, where we want to see all failures of a build at once. The -fn option hides failures from scripts, so it should be used with care.

$ mvn package -Dbroken=true -fae
[INFO] shop ............................................... SUCCESS [  0.002 s]
[INFO] common ............................................. SUCCESS [  2.021 s]
[INFO] orders ............................................. SUCCESS [  0.692 s]
[INFO] app ................................................ SUCCESS [  0.052 s]
[ERROR] reports ............................................ FAILURE [  0.680 s]
[ERROR] BUILD FAILURE
...
$ mvn package -Dbroken=true -fn
[INFO] shop ............................................... SUCCESS [  0.002 s]
[INFO] common ............................................. SUCCESS [  1.551 s]
[INFO] orders ............................................. SUCCESS [  0.485 s]
[INFO] app ................................................ SUCCESS [  0.015 s]
[ERROR] reports ............................................ FAILURE [  0.565 s]
[ERROR] BUILD FAILURE
[INFO] Build failures were ignored.
$ echo $?
0

Resuming with -rf

The -rf (--resume-from) option starts the build at the given module and builds it and all modules after it in the reactor order.

The resumed build fails. The common module comes before reports, so it is not part of the build, and Maven 3 looks for it in the local repository. Resuming works when the earlier modules were installed with mvn install; with mvn package, we must rebuild them, for instance with -pl reports -am.

$ mvn package -rf :reports
[INFO] reports                                                            [jar]
[INFO] orders                                                             [jar]
[INFO] app                                                                [jar]
[ERROR] BUILD FAILURE
[ERROR] Failed to execute goal on project reports: Could not resolve dependencies for project com.example:reports:jar:1.0.0
[ERROR] dependency: com.example:common:jar:1.0.0 (compile)
...

Parallel builds

The -T (--threads) option builds independent modules in parallel. The value is a number of threads, such as -T 4, or a multiple of the CPU cores, such as -T 1C.

Here reports and orders can be built at the same time, because both need only common. Parallel builds help in projects with many independent modules; all plugins used in the build must be thread-safe, and Maven warns about those that are not.

$ mvn package -T 4
[INFO] Using the MultiThreadedBuilder implementation with a thread count of 4
[INFO] shop ............................................... SUCCESS [  0.002 s]
[INFO] common ............................................. SUCCESS [  2.019 s]
[INFO] reports ............................................ SUCCESS [  0.878 s]
[INFO] orders ............................................. SUCCESS [  0.947 s]
[INFO] app ................................................ SUCCESS [  0.064 s]
[INFO] BUILD SUCCESS
...

Controlling the output

The -q (--quiet) option shows only errors, so a successful build prints nothing. The -X (--debug) option prints debug output, including the effective configuration of every plugin goal; it is long, so we show only the beginning.

Other output options:

The -N (--non-recursive) option, used in the debug example, builds only the project in the current directory, not its modules.

$ mvn -q package
$ mvn -X validate -N | head -6
Apache Maven 3.10.0 (c43a36b8d67be7e0805a411bc0898af1a51f5472)
Maven home: /home/user/.sdkman/candidates/maven/current
Java version: 25.0.3, vendor: Amazon.com Inc., runtime: /home/user/.sdkman/candidates/java/25.0.3-amzn
Default locale: en, platform encoding: UTF-8, time zone: Europe/Bratislava
OS name: "linux", version: "6.8.0-138-generic", arch: "amd64", family: "unix"
[DEBUG] Created lock factory selector; available lock factories [file-lock, rwlock-local, semaphore-local, noop]

Properties

The -D option sets a property: -Dname=value, or -Dname for the value true. Plugins read many of their parameters from such properties. A common example is skipping tests.

The skipTests property compiles the tests but does not run them. The maven.test.skip property skips the compilation of the tests too. In most cases skipTests is the better choice; with maven.test.skip, test JARs are not built, so a module that uses the test classes of another module can fail.

$ mvn package -pl common -DskipTests
[INFO] --- compiler:3.16.0:testCompile (default-testCompile) @ common ---
[INFO] Compiling 1 source file with javac [debug release 25] to target/test-classes
[INFO] --- surefire:3.6.1:test (default-test) @ common ---
[INFO] Tests are skipped.
...
$ mvn package -pl common -Dmaven.test.skip=true
[INFO] --- compiler:3.16.0:testCompile (default-testCompile) @ common ---
[INFO] Not compiling test sources
[INFO] --- surefire:3.6.1:test (default-test) @ common ---
[INFO] Tests are skipped.
...

Offline and update options

The -o (--offline) option forbids network access. Maven uses only the artifacts already in the local repository. This is handy without a network connection and on build servers that must not download anything. To demonstrate it, we use a second small project.

pom.xml (dependencies)
<dependencies>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-text</artifactId>
        <version>1.11.0</version>
    </dependency>
</dependencies>

The project depends on commons-text 1.11.0, a version that was never downloaded to our local repository.

In offline mode, Maven fails and tells us which artifact is missing. The dependency:go-offline goal downloads everything a project needs in advance. The opposite option, -U (--update-snapshots), makes Maven check the remote repositories for newer snapshot versions and refresh the cached metadata, instead of waiting for the daily update.

$ mvn -o compile
[ERROR] BUILD FAILURE
[ERROR] Failed to execute goal on project offline: Could not resolve dependencies for project com.example:offline:jar:1.0.0
[ERROR] dependency: org.apache.commons:commons-text:jar:1.11.0 (compile)
[ERROR] 	Cannot access central (https://repo.maven.apache.org/maven2) in offline mode and the artifact org.apache.commons:commons-text:jar:1.11.0 has not been downloaded from it before.
...

The .mvn/maven.config file

Options that a project always needs can be stored in the .mvn/maven.config file in the root directory of the project. Maven reads it on every run and adds its contents to the command line. Since Maven 3.9, each option must be on its own line. The .mvn/jvm.config file holds options for the JVM that runs Maven.

The -DskipTests option from maven.config skipped the tests, although we did not type it. The system property from jvm.config is visible to Maven like any other property. Both files belong to the project and are committed to version control, so all developers and the CI server get the same defaults. For personal settings, the MAVEN_OPTS environment variable passes options to the JVM.

$ cat .mvn/maven.config
--batch-mode
--no-transfer-progress
-DskipTests
$ cat .mvn/jvm.config
-Xmx512m -Dbuild.env=ci
$ mvn package -pl common
[INFO] --- surefire:3.6.1:test (default-test) @ common ---
[INFO] Tests are skipped.
[INFO] BUILD SUCCESS
...
$ mvn -q help:evaluate -Dexpression=build.env -DforceStdout -N
ci

The MAVEN_ARGS variable

Since Maven 3.9, the MAVEN_ARGS environment variable holds options that are added to every mvn command. It is meant for personal defaults, such as -ntp, that should not be committed to the project.

The options from the variable selected the app module and its dependencies, as if we typed -pl app -am.

$ MAVEN_ARGS="-pl app -am" mvn package
[INFO] shop ............................................... SUCCESS [  0.002 s]
[INFO] common ............................................. SUCCESS [  2.140 s]
[INFO] orders ............................................. SUCCESS [  0.742 s]
[INFO] app ................................................ SUCCESS [  0.053 s]
[INFO] BUILD SUCCESS
...

Summary of options

OptionLong formMeaning
-pl--projectsbuild only the given modules
-am--also-makealso build the dependencies of the selected modules
-amd--also-make-dependentsalso build the modules that depend on the selected modules
-rf--resume-fromresume the build from a module
-N--non-recursivedo not build the modules
-f--fileuse another POM file or directory
-fae--fail-at-endcontinue with independent modules after a failure
-fn--fail-nevernever fail the build
-T--threadsbuild modules in parallel
-o--offlinework offline
-U--update-snapshotscheck for updated snapshots
-D--defineset a property
-P--activate-profilesactivate or deactivate profiles
-s--settingsuse another user settings.xml file
-q--quietshow only errors
-X--debugshow debug output
-e--errorsshow stack traces of errors
-B--batch-moderun non-interactively
-ntp--no-transfer-progresshide download progress

Source

Maven CLI options reference

In this article we have covered the most useful options of the Maven command line.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Java tutorials.