JPackage : Create MSI/EXE Installer for Java App

The jpackage is a command-line tool introduced in Java 14 and helps create native installable packages (.exe, .msi, .dmg, .pkg, .deb, .rpm) for Windows, macOS, and Linux. Jpackage bundles Java applications along with a Java runtime (JRE) image, ensuring that end users do not need to install Java separately.

jpackage tool

The jpackage is a command-line tool introduced in Java 14 and helps create native installable packages (.exe, .msi, .dmg, .pkg, .deb, .rpm) for Windows, macOS, and Linux. Jpackage bundles Java applications along with a Java runtime (JRE) image, ensuring that end users do not need to install Java separately.

JPackage allows for various desktop integration features such as creating application shortcuts (system menu, desktop shortcut), file associations, etc.

1. Prerequisites

Before using jpackage, make sure we have the following available in the system:

  • Java 14 or later (the latest version is recommended).
  • The application is packaged as a fat jar file i.e. all necessary dependencies are bundled into the jar.
  • On Linux and macOS, we must have the following packages:
    • Windows: Wix 3.x
    • Linux: dpkg (Debian-based) or rpm (RedHat-based)
    • macOS: Xcode Command Line Tools

2. Steps to Use JPackage

There are two ways to use the jpackage tool:

  • Using command line
  • Using maven plugin

2.1. Using ‘jpackage‘ Command

To use the jpackage, for packaging an application we must make sure that the fat jar version of the application is already present.

Assuming that the fat jar name is: ‘myapp-jar-with-dependencies.jar‘: we can run the following command to create a .msi package for Windows installation. The type can be msi or exe.

jpackage \
  --type exe \
  --input . \
  --name MyApp \
  --main-jar myapp-jar-with-dependencies.jar \
  --main-class com.example.Main \
  --icon myapp.ico \
  --win-menu \
  --win-shortcut

Similarly, for macOS, we can run the following command. The type can be dmg or pkg.

jpackage \
  --type dmg \
  --input . \
  --name MyApp \
  --main-jar myapp-jar-with-dependencies.jar \
  --main-class com.example.Main \
  --icon myapp.icns \
  --mac-package-identifier com.example.myapp \
  --mac-sign

Similarly, for macOS, we can run the following command. The type can be deb or rpm.

jpackage \
  --type deb \
  --input . \
  --name MyApp \
  --main-jar myapp-jar-with-dependencies.jar \
  --main-class com.example.Main \
  --icon myapp.png \
  --linux-package-name myapp

2.2. JPackage Maven Plugin

The most effective and recommended way is to use the jpackage maven plugin. Make sure you have set the JAVA_HOME environment variable pointing to the JDK which you want to use for jpackage.

The configuration has the following plugins:

  • maven-compiler-plugin: for compiling the application using the configured JDK version.
  • maven-assembly-plugin: for making the fat-jar from the application jar and all its dependencies.
  • jpackage-maven-plugin: for packaging the application as an MSI installer.
...
<packaging>jar</packaging>
...
<properties>
    <app.name>My Application Name</app.name>
    <app.version>1.0.0</app.version>
    <vendor.name>My Company Name</vendor.name>
    <copyright>Copyright@2025</copyright>
    <maven.compiler.source>21</maven.compiler.source>
    <maven.compiler.target>${maven.compiler.source}</maven.compiler.target>
    <lombok.version>1.18.36</lombok.version>
</properties>
...
<build>
    <finalName>${app.name}-${app.version}</finalName>
    <pluginManagement>
      <plugins>

        <plugin>
          <groupId>com.github.akman</groupId>
          <artifactId>jpackage-maven-plugin</artifactId>
          <version>0.1.5</version>
          <executions>
            <execution>
              <goals>
                <goal>jpackage</goal>
              </goals>
            </execution>
          </executions>
          <configuration>
            <name>${app.name}</name>
            <appversion>${app.version}</appversion>
            <copyright>${copyright}</copyright>
            <vendor>${vendor.name}</vendor>
            <mainjar>${app.name}-${app.version}-jar-with-dependencies.jar</mainjar>
            <input>target/</input>
            <mainclass>com.example.app.SwingApplication</mainclass>
            <type>MSI</type>
            <javaoptions>--enable-preview</javaoptions>
            <dest>.</dest>
            <icon>${project.basedir}/src/main/resources/app-icon.ico</icon>
            <winconsole>false</winconsole>
            <winmenu>true</winmenu>
            <winshortcut>true</winshortcut>
          </configuration>
        </plugin>

      </plugins>
    </pluginManagement>
    <plugins>

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.11.0</version>
        <configuration>
          <source>${maven.compiler.source}</source>
          <target>${maven.compiler.source}</target>
          <release>${maven.compiler.source}</release>
          <annotationProcessorPaths>
            <path>
              <groupId>org.projectlombok</groupId>
              <artifactId>lombok</artifactId>
              <version>${lombok.version}</version>
            </path>
          </annotationProcessorPaths>
        </configuration>
      </plugin>

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>3.3.0</version>
        <configuration>
          <archive>
            <manifest>
              <mainClass>com.example.app.SwingApplication</mainClass>
            </manifest>
          </archive>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
        </configuration>
        <executions>
          <execution>
            <id>make-assembly</id>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
      </plugin>

      <plugin>
        <groupId>com.github.akman</groupId>
        <artifactId>jpackage-maven-plugin</artifactId>
        <executions>
          <execution>
            <id>jpackage-installer</id>
            <phase>verify</phase>
            <goals>
              <goal>jpackage</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

2.3. How to Run Jpackage Command

Once you configured all the required and optional properties, you can run the following maven command for building the fat jar and the package it as an installer.

$ mvn clean install
$mvn jpackage:jpackage

This will create the MSI installer file in the project base directory.

3. Important JPackage Parameters

The following is the list of important parameters to pass while packaging an installer file:

ParameterDescription
--inputSpecifies the input directory where the application JAR is located
--nameSets the name of the application package
--main-jarSpecifies the main application JAR file
--main-classDefines the main class with the main() method
--typeDefines the package type (exe, msi, dmg, pkg, deb, rpm)
--iconSets the application icon file
--app-versionSpecifies the version of the application
--win-menuCreates a Windows Start Menu entry
--win-shortcutCreates a Windows desktop shortcut
--linux-package-nameSets the package name for Linux installers
--mac-signSigns the macOS package (requires signing identity)

4. Conclusion

jpackage is a very effective tool for creating native installers for Java desktop applications. It eliminates the need to have 3rd-party software for this specific purpose which involves extra cost and expertise.

By integrating the jpackage plugin in the maven build life-cycle, we can create an installer file as quickly as making a runnable jar file.

Happy Learning !!

Weekly Newsletter

Stay Up-to-Date with Our Weekly Updates. Right into Your Inbox.

Comments

Subscribe
Notify of
0 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.