Last Updated:
How to Create an Executable JAR with Dependencies Using Maven: Step-by-Step Guide
Java applications are typically distributed as JAR (Java Archive) files, but a basic JAR only contains your compiled code—not its dependencies (e.g., libraries like Spring Boot, Gson, or Apache Commons). This means users would need to manually include dependencies on their classpath to run your app, which is impractical.
An executable JAR with dependencies (sometimes called a "fat JAR" or "uber JAR") bundles your application code and all required dependencies into a single file. This makes distribution and execution seamless: users can run your app with a simple java -jar your-app.jar command.
In this guide, we’ll use Apache Maven—the most popular build tool for Java—to create such an executable JAR. We’ll cover two common Maven plugins: the Maven Shade Plugin (recommended for flexibility) and the Maven Assembly Plugin (a simpler alternative). By the end, you’ll be able to package your Java app into a standalone, runnable JAR.
Table of Contents#
- Prerequisites
- Understanding Executable JARs and Dependencies
- Step-by-Step Guide
- Troubleshooting Common Issues
- Conclusion
- References
Prerequisites#
Before starting, ensure you have the following installed:
- Java Development Kit (JDK) 8 or higher: Maven requires Java to run. Verify with
java -versionin your terminal. - Apache Maven 3.6 or higher: Install from Maven’s official site. Verify with
mvn -version. - A text editor or IDE: Use VS Code, IntelliJ IDEA, Eclipse, or any editor of your choice.
Understanding Executable JARs and Dependencies#
What is an Executable JAR?#
A standard JAR file contains compiled Java classes, but it won’t run unless you explicitly specify the classpath (with dependencies) and the main class. An executable JAR includes:
- Your application’s compiled code.
- All required dependencies (libraries, frameworks, etc.).
- A
META-INF/MANIFEST.MFfile with aMain-Classentry (tells the JVM which class to execute).
Why Bundle Dependencies?#
Without bundling dependencies, users would need to:
- Download your JAR.
- Manually download all dependencies and place them in a folder.
- Run the app with
java -cp "your-app.jar:dependency1.jar:dependency2.jar" com.yourpackage.MainClass.
An executable JAR eliminates this hassle by packaging everything into one file: java -jar your-app.jar.
Step-by-Step Guide#
3.1 Set Up a Maven Project#
First, create a new Maven project. We’ll use the maven-archetype-quickstart archetype to generate a basic project structure.
-
Open your terminal and run the following command:
mvn archetype:generate -DgroupId=com.example -DartifactId=executable-jar-demo -Dversion=1.0-SNAPSHOT -DinteractiveMode=falsegroupId: Typically your organization’s domain (e.g.,com.example).artifactId: Name of your project (e.g.,executable-jar-demo).version: Project version (e.g.,1.0-SNAPSHOT).
-
Navigate to the project directory:
cd executable-jar-demo
Your project structure will look like this:
executable-jar-demo/
├── pom.xml # Maven configuration file
├── src/
│ ├── main/
│ │ └── java/
│ │ └── com/
│ │ └── example/
│ │ └── App.java # Default main class (we’ll modify this)
│ └── test/
│ └── java/
│ └── com/
│ └── example/
│ └── AppTest.java
└── target/ # Generated files (JARs, classes, etc.)
3.2 Write a Simple Java Class with a Main Method#
We’ll use a basic Java class with a main method to test the executable JAR.
-
Open
src/main/java/com/example/App.javain your editor. Replace its contents with:package com.example; public class App { public static void main(String[] args) { System.out.println("Hello, Executable JAR!"); // Add a dependency to demonstrate bundling (e.g., Gson) com.google.gson.Gson gson = new com.google.gson.Gson(); System.out.println("Gson version: " + gson.getClass().getPackage().getImplementationVersion()); } }Note: This code uses Google’s Gson library (a JSON parser) to demonstrate bundling a dependency. We’ll add Gson to
pom.xmllater.
3.3 Configure pom.xml to Package Dependencies#
The pom.xml file defines your project’s dependencies and build process. To bundle dependencies, we’ll use a Maven plugin. We’ll cover two options:
Option 1: Use the Maven Shade Plugin (Recommended)#
The Maven Shade Plugin is the most flexible tool for creating fat JARs. It merges dependencies into the JAR and handles edge cases like duplicate files (e.g., META-INF/LICENSE files from different libraries).
-
Open
pom.xmland add the Shade Plugin to the<build><plugins>section. Also, add the Gson dependency (so we can test bundling):<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>executable-jar-demo</artifactId> <version>1.0-SNAPSHOT</version> <name>executable-jar-demo</name> <url>http://maven.apache.org</url> <properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <!-- Add dependencies here --> <dependencies> <!-- Gson: A sample dependency to bundle --> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.10.1</version> </dependency> <!-- JUnit for testing (optional) --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> <!-- Build configuration --> <build> <plugins> <!-- Maven Shade Plugin to bundle dependencies --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.4.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <!-- Specify the main class (required for execution) --> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>com.example.App</mainClass> <!-- Replace with your main class --> </transformer> <!-- Optional: Merge service files (e.g., for SPI implementations) --> <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/> </transformers> <!-- Optional: Filter dependencies to exclude (e.g., test scopes) --> <filters> <filter> <artifact>*:*</artifact> <excludes> <exclude>META-INF/*.SF</exclude> <exclude>META-INF/*.DSA</exclude> <exclude>META-INF/*.RSA</exclude> </excludes> </filter> </filters> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>Key Configuration Details:
<mainClass>: Tells the JVM which class contains themainmethod (replacecom.example.Appwith your class path).<transformers>: Merges files likeMETA-INF/MANIFEST.MFand service files to avoid conflicts.<filters>: Excludes unnecessary files (e.g., signature files) to reduce JAR size.
Option 2: Use the Maven Assembly Plugin (Simpler)#
The Maven Assembly Plugin is simpler but less flexible than Shade. It uses "descriptor references" to define packaging behavior (e.g., jar-with-dependencies).
-
Replace the Shade Plugin in
pom.xmlwith the Assembly Plugin:<build> <plugins> <!-- Maven Assembly Plugin --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <version>3.6.0</version> <configuration> <archive> <manifest> <mainClass>com.example.App</mainClass> <!-- Your main class --> </manifest> </archive> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> <!-- Bundles all dependencies --> </descriptorRefs> </configuration> <executions> <execution> <id>make-assembly</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin> </plugins> </build>Limitation: The Assembly Plugin may not handle duplicate files as gracefully as Shade, leading to warnings or corrupted JARs. Use Shade for production apps.
3.4 Build the Executable JAR#
Now, build the JAR using Maven:
-
Run the following command in your project directory:
mvn clean packageclean: Deletes thetarget/directory (old builds).package: Compiles code, runs tests, and packages the JAR.
-
After the build succeeds, check the
target/directory. You’ll see:- For Shade Plugin:
executable-jar-demo-1.0-SNAPSHOT.jar(the fat JAR). - For Assembly Plugin:
executable-jar-demo-1.0-SNAPSHOT-jar-with-dependencies.jar(the fat JAR) and a regular JAR.
- For Shade Plugin:
3.5 Test the Executable JAR#
Run the JAR to verify it works:
-
For Shade Plugin:
java -jar target/executable-jar-demo-1.0-SNAPSHOT.jar -
For Assembly Plugin:
java -jar target/executable-jar-demo-1.0-SNAPSHOT-jar-with-dependencies.jar
Expected Output:
Hello, Executable JAR!
Gson version: 2.10.1
If you see this, congratulations! Your JAR includes the Gson dependency and runs successfully.
Troubleshooting Common Issues#
"No Main Manifest Attribute" Error#
Cause: The META-INF/MANIFEST.MF file is missing the Main-Class entry.
Fix: Ensure <mainClass> is correctly set in the plugin configuration (e.g., com.example.App).
"ClassNotFoundException" for Dependencies#
Cause: The dependency wasn’t bundled into the JAR.
Fix:
- Verify the dependency is in
pom.xmlwith<scope>compile</scope>(default). - Run
mvn dependency:treeto check if the dependency is included.
Duplicate File Warnings During Build#
Cause: Multiple dependencies include the same file (e.g., META-INF/LICENSE).
Fix: Use the Shade Plugin with <filters> to exclude duplicate files (see the Shade Plugin example above).
JAR is Too Large#
Fix: Exclude unnecessary dependencies with <exclusions> in pom.xml, or use mvn dependency:analyze to identify unused dependencies.
Conclusion#
Creating an executable JAR with Maven is a critical skill for distributing Java applications. By following this guide, you’ve learned:
- How to set up a Maven project and add dependencies.
- How to use the Maven Shade Plugin (recommended) or Assembly Plugin to bundle dependencies.
- How to build and test the executable JAR.
For advanced use cases, explore:
- Customizing the JAR name (add
<finalName>my-app</finalName>to<build>inpom.xml). - Excluding specific dependencies with
<exclusions>inpom.xml. - Signing the JAR for security.