ZetCode

Maven Exec Plugin

last modified June 11, 2025

The Maven Exec Plugin lets you run Java programs and system commands from Maven. It's ideal for development, allowing quick execution without building a JAR file.

The plugin supports two goals: exec:java for running Java classes and exec:exec for executing system commands or scripts. This tutorial covers configuring and using the plugin with practical examples.

Basic Configuration

To use the Maven Exec Plugin, add it to your pom.xml under the build section. Below is an example configuration for running a Java main class during the package phase.

pom.xml
<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>exec-example</artifactId>
    <version>1.0.0</version>
    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>
    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>3.1.0</version>
                <executions>
                    <execution>
                        <id>run-app</id>
                        <phase>package</phase>
                        <goals>
                            <goal>java</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <mainClass>com.example.MainApp</mainClass>
                    <cleanupDaemonThreads>false</cleanupDaemonThreads>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
<mainClass>com.example.MainApp</mainClass>

This specifies the fully qualified name of the Java class with the main method to execute. The cleanupDaemonThreads option ensures threads are handled properly during shutdown.

Running the Application

You can run the application using the exec:java goal, specifying the main class via a system property if not configured in the POM.

mvn exec:java -Dexec.mainClass="com.example.MainApp"

If the plugin is configured in the pom.xml with an execution bound to the package phase, simply run:

mvn package

This compiles the code and executes the configured main class. Here's a sample Java application to demonstrate.

src/main/java/com/example/MainApp.java
package com.example;

public class MainApp {
    public static void main(String[] args) {
        System.out.println("Hello from Maven Exec Plugin!");
        for (String arg : args) {
            System.out.println("Argument: " + arg);
        }
        String prop = System.getProperty("app.name", "Unknown");
        System.out.println("App Name: " + prop);
    }
}

Running mvn package or mvn exec:java will execute this class, printing a greeting and any passed arguments or system properties.

Passing Arguments

You can pass command-line arguments to your Java application either via the command line or by configuring them in the pom.xml.

Command Line
mvn exec:java -Dexec.mainClass="com.example.MainApp" -Dexec.args="arg1 arg2 arg3"

This passes "arg1", "arg2", and "arg3" to the main method. Alternatively, configure arguments in the pom.xml:

pom.xml
<configuration>
    <mainClass>com.example.MainApp</mainClass>
    <arguments>
        <argument>input.txt</argument>
        <argument>output.txt</argument>
    </arguments>
</configuration>

These arguments are passed to the main method's String[] args parameter, useful for file names, flags, or other runtime inputs.

System Properties

System properties can be passed to customize the JVM or application behavior. This is done via the command line or in the pom.xml.

Command Line
mvn exec:java -Dexec.mainClass="com.example.MainApp" \
    -Dapp.name="MyApp" -Denv=dev

Alternatively, configure system properties in the pom.xml:

pom.xml
<configuration>
    <mainClass>com.example.MainApp</mainClass>
    <systemProperties>
        <property>
            <key>app.name</key>
            <value>MyApp</value>
        </property>
        <property>
            <key>env</key>
            <value>dev</value>
        </property>
    </systemProperties>
</configuration>

These properties are accessible via System.getProperty in your Java code, as shown in the MainApp example above.

Classpath Configuration

The Exec Plugin allows you to customize the classpath used when running the application, controlling which dependencies are included.

pom.xml
<configuration>
    <mainClass>com.example.MainApp</mainClass>
    <classpathScope>runtime</classpathScope>
    <includePluginDependencies>false</includePluginDependencies>
    <includeProjectDependencies>true</includeProjectDependencies>
    <additionalClasspathElements>
        <additionalClasspathElement>${project.basedir}/lib/extra.jar</additionalClasspathElement>
    </additionalClasspathElements>
</configuration>
<classpathScope>runtime</classpathScope>

Defines which dependency scope to include (e.g., compile, runtime, test). includePluginDependencies controls whether plugin dependencies are included, and additionalClasspathElements adds custom JARs.

Executing External Programs

The exec:exec goal runs system commands or scripts, such as Python scripts, shell commands, or other executables.

pom.xml
<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>exec-maven-plugin</artifactId>
    <version>3.1.0</version>
    <executions>
        <execution>
            <id>run-script</id>
            <phase>generate-resources</phase>
            <goals>
                <goal>exec</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <executable>python3</executable>
        <arguments>
            <argument>${project.basedir}/scripts/process.py</argument>
            <argument>--input</argument>
            <argument>data.txt</argument>
        </arguments>
    </configuration>
</plugin>

This example runs a Python script during the generate-resources phase. The executable must be available in the system PATH.

Multiple Executions

You can configure multiple executions to run different programs or classes at different Maven phases, such as running a main class and a utility tool.

pom.xml
<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>exec-maven-plugin</artifactId>
    <version>3.1.0</version>
    <executions>
        <execution>
            <id>run-main</id>
            <phase>package</phase>
            <goals>
                <goal>java</goal>
            </goals>
            <configuration>
                <mainClass>com.example.MainApp</mainClass>
                <arguments>
                    <argument>start</argument>
                </arguments>
            </configuration>
        </execution>
        <execution>
            <id>run-tool</id>
            <phase>verify</phase>
            <goals>
                <goal>java</goal>
            </goals>
            <configuration>
                <mainClass>com.example.DataValidator</mainClass>
                <arguments>
                    <argument>check</argument>
                </arguments>
            </configuration>
        </execution>
        <execution>
            <id>run-script</id>
            <phase>process-resources</phase>
            <goals>
                <goal>exec</goal>
            </goals>
            <configuration>
                <executable>bash</executable>
                <arguments>
                    <argument>${project.basedir}/scripts/cleanup.sh</argument>
                </arguments>
            </configuration>
        </execution>
    </executions>
</plugin>

This configuration runs a Java main class, a validation tool, and a shell script at different phases, showcasing the plugin's flexibility.

src/main/java/com/example/DataValidator.java
package com.example;

public class DataValidator {
    public static void main(String[] args) {
        System.out.println("Running DataValidator with args: " + String.join(", ", args));
        // Simulate validation logic
        boolean valid = "check".equals(args.length > 0 ? args[0] : "");
        System.out.println("Data validation: " + (valid ? "Success" : "Failure"));
    }
}

This DataValidator class simulates a validation process, printing the arguments passed to it. You can run the entire Maven build with:

$ mvn package

This will execute all configured executions in the specified phases, running the main class, the data validator, and the shell script in sequence.

Debugging Support

The Exec Plugin supports JVM debugging by passing debug flags. This is useful for troubleshooting or stepping through code in an IDE.

Command Line
mvn exec:java -Dexec.mainClass="com.example.MainApp" \
    -Dexec.jvmArgs="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005"

Or configure in the pom.xml:

pom.xml
<configuration>
    <mainClass>com.example.MainApp</mainClass>
    <jvmArguments>
        <jvmArgument>-Xdebug</jvmArgument>
        <jvmArgument>-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005</jvmArgument>
    </jvmArguments>
</configuration>

This starts the JVM in debug mode, listening on port 5005, allowing you to connect with a debugger (e.g., IntelliJ IDEA or Eclipse).

Environment Variables

You can set environment variables for the executed program, useful for configuring external tools or Java applications.

pom.xml
<configuration>
    <mainClass>com.example.MainApp</mainClass>
    <environmentVariables>
        <JAVA_HOME>/usr/lib/jvm/java-17</JAVA_HOME>
        <APP_ENV>development</APP_ENV>
    </environmentVariables>
</configuration>

These variables are available to the Java application via System.getenv or to external programs like scripts.

src/main/java/com/example/EnvApp.java
package com.example;

public class EnvApp {
    public static void main(String[] args) {
        String env = System.getenv("APP_ENV");
        System.out.println("Environment: " + (env != null ? env : "Not set"));
    }
}

The above code retrieves the APP_ENV variable, printing its value or indicating it is not set. Run it with:

mvn exec:java -Dexec.mainClass="com.example.EnvApp"

This will output the environment variable value, demonstrating how to pass environment variables to your application.

Working Directory Configuration

You can specify the working directory for the executed program, which affects where file operations are performed.

pom.xml
<configuration>
    <mainClass>com.example.MainApp</mainClass>
    <workingDirectory>${project.basedir}/target</workingDirectory>
</configuration>

This sets the working directory to the target folder, useful for accessing generated files or outputs during execution.

Error Handling and Exit Codes

The Exec Plugin can handle program exit codes to control the build process. For example, you can fail the build if the program exits with a non-zero code.

pom.xml
<configuration>
    <mainClass>com.example.MainApp</mainClass>
    <successCodes>
        <successCode>0</successCode>
        <successCode>1</successCode>
    </successCodes>
</configuration>

This configuration treats exit codes 0 and 1 as successful, preventing the build from failing. Here's an example showing exit code usage:

src/main/java/com/example/ExitCodeApp.java
package com.example;

public class ExitCodeApp {
    public static void main(String[] args) {
        System.out.println("Running ExitCodeApp");
        if (args.length > 0 && "fail".equals(args[0])) {
            System.exit(2); // Non-success exit code
        } else {
            System.exit(0); // Success exit code
        }
    }
}

This application exits with code 2 if the argument "fail" is passed, or 0 otherwise. You can run it with the Exec Plugin to see how exit codes are handled.

Run with:

mvn exec:java -Dexec.mainClass="com.example.ExitCodeApp" -Dexec.args="fail"

Without successCodes, a non-zero exit code would fail the build.

Best Practices

Here are best practices for using the Maven Exec Plugin effectively:

Source

Exec Maven Plugin Docs

In this article, we explored how to use the Maven Exec Plugin to run Java applications and external programs directly from Maven, with practical examples and best practices for configuration and troubleshooting.

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.