Use jpackage to Create Native Java App Installers




jpackage is a new tool with JDK 14 that generates native system installers for distributing your appliction. It will create .msi for Windows, .dmg for Mac, and .deb or .rpm for Linux distrubtions. This is ideal for GUI applications. This guide will demonstrate how to use this tool to create system native installers for your applications.

jlink vs jpackage

jlink was introduced in Java 9 and jpackage builds on top of jlink and came with Java 14. jpackage uses jlink under the hood.

To understand jlink better, check out my tutorial How to Create Java Runtime Images with jlink.

You can manually perform the jlink step before running jpackage, otherwise jpackage automatically invokes jlink during the process jlink generates the executable (e.g. .exe, .app), but jpackage creates the installer for the executable (e.g. .msi, .dmg, .deb, .rpm).

Packaging non-modular apps

Though jpackage only supports JDK11+, you can still build traditional non-modular apps.

This is the simplest example to demonstrate how jpackage works. You take an executable jar file, in this case myapp.jar, and specify the class inside that you want to execute. The input directory tells jpackage where to look for the JAR.

# input dir is where the main jar resides (`target/` typically with Maven projects)
# main jar path should be relative to the input dir
# main class is the executable class with a main() method
jpackage -i ./target/ --main-class com.devdungeon.Main --main-jar myapp.jar

This generates a single standalone .exe file that will install your application.

Packaging modular apps

With a modular app, you have a couple options. You could use jlink to build the runtime image first. You could include your application and dependencies in this runtime, or you can use jpackage to

Automatically generate a runtime image

jpackage will automatically run jlink and generate a runtime with the modules needed. There is no need to run jlink yourself unless you want something very custom. This example will generate the runtime and installer package with your module.

jpackage \
 --module-path .;target/my.jar \
 --module mymodule/com.devdungeon.Main \
 --add-modules java.desktop,mymodule \

Use a custom runtime image

If you already have a runtime image with the modules in it, you can simply tell jpackage to use the runtime image you want with the --runtime-image option. Specify the main class with the --module option.

To learn how to create a custom runtime, check out my tutorial How to Create Java Runtime Images with jlink.

Here is an example of packaging an existing runtime to run a specific class.

jpackage \
  --runtime-image my-custom-jre-with-app \
  --module mymodule/com.devdungeon.Main

Add a startup splash screen

# APPDIR resolves to app final install dir
--java-options '-splash:$APPDIR/splash.png'

Associating file extensions with your app


For example, if I wanted to create a file extension .dano for my application. You can specify the following things for your custom file type:

  • the file icon
  • the mime-type you want to use
  • the file extension

Common Windows options

Here are a few useful options when generating a Windows installer.

Let users choose the install directory


Creating a console launcher

# Create a console launcher for CLI applications

Creating Start menu entry

# Add app to start menu
# defaults to "Unknown" folder without --win-menu-group
--win-menu-group <name>
# Create desktop shortcut

Install for user instead of system-wide



After reading this guide, you should understand how to use jpackage to generate a system-native installer for a Java application whether it is module or non-modular.