How to Package Java Swing Applications into Standalone Executables Without a JRE

This guide compares common Java desktop packaging methods, evaluates their pros and cons, and demonstrates a custom Winform tool that bundles a Swing program and a minimal JRE into a single executable for easy distribution.

macrozheng
macrozheng
macrozheng
How to Package Java Swing Applications into Standalone Executables Without a JRE

Packaging Options for Java Swing Applications

Compile the JAR into a native binary with GraalVM.

Use JLink to create a custom runtime image and package it as a binary.

Generate a launcher with Exe4J and wrap it in a self‑extracting archive.

Write a batch script and wrap it in a self‑extracting archive.

Distribute the plain JAR and require users to install a JRE manually.

Advantages and Disadvantages

GraalVM : Improves performance and reduces resource consumption, but build time is long, debugging is difficult, and reflection support is limited.

JLink : Produces a lightweight binary with a bundled runtime, yet the build process is complex and the resulting file can be relatively large.

Exe4J : Lowers the entry barrier and provides a better user experience, but the executable still includes a full JRE, making the size large.

Batch script : Flexible and easy to update, but also results in a large package that requires a JRE.

Plain JAR : Small file size and easy updates, but cannot run on machines without a JRE and offers a poor user experience.

Custom Winform Packaging Tool

A Winform application automates the creation of a self‑contained Windows executable. The workflow is:

Assemble a "fat JAR" that contains all project dependencies.

Use jlink (or the tool’s built‑in logic) to generate a minimal JRE that includes only the modules required by the application.

Bundle the fat JAR and the trimmed JRE into a self‑extracting .exe that can be launched with a double‑click.

Example Maven Project

The following pom.xml configures Maven to produce a fat JAR with the maven-assembly-plugin and sets the main class.

<?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>org.helloswing</groupId>
  <artifactId>HelloSwing</artifactId>
  <version>1.0-SNAPSHOT</version>
  <properties>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  <dependencies>
    <dependency>
      <groupId>com.formdev</groupId>
      <artifactId>flatlaf</artifactId>
      <version>3.5.1</version>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>3.7.1</version>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
          <appendAssemblyId>false</appendAssemblyId>
          <archive>
            <manifest>
              <mainClass>org.helloswing.HelloSwing</mainClass>
            </manifest>
          </archive>
        </configuration>
        <executions>
          <execution>
            <id>make-assembly</id>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

The main class HelloSwing.java creates a simple window using FlatLaf for theming.

package org.helloswing;

import com.formdev.flatlaf.FlatDarkLaf;
import com.formdev.flatlaf.FlatLightLaf;
import javax.swing.*;
import java.awt.*;

public class HelloSwing {
    public static void main(String[] args) throws UnsupportedLookAndFeelException {
        // Install look‑and‑feel
        FlatLightLaf.install();
        UIManager.setLookAndFeel(new FlatDarkLaf());
        // Create window
        JFrame frame = new JFrame("Hello Swing!");
        frame.setSize(500, 500);
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        JPanel panel = new JPanel(new BorderLayout());
        panel.add(new JLabel("Hello Swing!", JLabel.CENTER), BorderLayout.CENTER);
        frame.getContentPane().add(panel);
        frame.setVisible(true);
    }
}

Build and Package Process

Run mvn clean package to generate the fat JAR.

Use jlink (or the custom Winform tool) to create a minimal JRE that contains only the modules required by the application.

Combine the generated JAR and the custom JRE into a self‑extracting Windows executable using the Winform utility.

The resulting .exe can be distributed and run on Windows machines without any pre‑installed Java runtime.

JavaPackagingGraalVMSwingExecutableJLink
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.