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.
<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.
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
.
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
:
<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
.
mvn exec:java -Dexec.mainClass="com.example.MainApp" \ -Dapp.name="MyApp" -Denv=dev
Alternatively, configure system properties in the 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.
<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.
<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.
<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.
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.
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
:
<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.
<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.
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.
<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.
<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:
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:
-
Explicitly configure the plugin - Define executions and
configurations in the
pom.xml
for consistent builds. - Use specific phases - Bind executions to appropriate Maven phases (e.g., package, verify) to integrate with the build lifecycle.
- Minimize command-line overrides - Prefer POM configurations over command-line arguments for reproducibility.
-
Handle threads properly - Set
cleanupDaemonThreads
to false to avoid issues with background threads. - Validate executables - Ensure system commands (e.g., python3) are available in the PATH to avoid execution failures.
- Use debugging wisely - Enable debug mode only when needed to avoid performance overhead in production builds.
-
Monitor exit codes - Configure
successCodes
to handle expected exit codes and prevent unnecessary build failures.
Source
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
List all Java tutorials.