Many Java developers struggle with delivering applications in a way that is both user-friendly and production-ready. A common pain point arises when developers modularize their applications but still distribute them as plain JARs, leaving end-users to deal with the classpath or module path manually. Others ship fat JARs, which undermine the benefits of JPMS.
This is where jmod and jpackage step in. Together, they allow developers to distribute self-contained, modular, and installable applications. jmod lets you package reusable Java modules, while jpackage helps create native installers and application bundles for smooth distribution.
Think of it like preparing a meal for guests: jmod is about carefully preparing ingredients into sealed containers (modules), while jpackage is about serving the complete dish with plates, cutlery, and everything needed to consume it.
Understanding jmod
What is a jmod file?
A .jmod file is a packaging format introduced in Java 9. It is similar to a JAR, but designed for modules, containing:
- Compiled classes
- Native libraries
- Configuration files
- Man pages or legal notices
Unlike JARs, jmod files are not intended for runtime distribution, but rather for creating runtime images with tools like jlink.
Example: Creating a jmod file
Assume we have a module com.example.lib.
module-info.java
module com.example.lib {
exports com.example.lib.api;
}
Compile the module:
javac -d out --module-source-path src $(find src -name "*.java")
Create a .jmod file:
jmod create --class-path out/com.example.lib --module-version 1.0 libs/com.example.lib.jmod
This produces com.example.lib.jmod, which can later be used in a custom runtime image.
Understanding jpackage
What is jpackage?
jpackage, introduced in Java 14, builds installable application bundles (e.g., .exe for Windows, .pkg for macOS, .deb for Linux). It ensures users can install and run your Java app like any native application.
Key benefits:
- Simplifies installation for end-users
- Packages a custom runtime with your application
- Provides OS-native experience (icons, shortcuts, uninstallers)
Example: Using jpackage
Suppose we have a modular application com.example.app.
Command to package:
jpackage --input out --main-jar com.example.app.jar --main-class com.example.app.Main --name MyApp --type dmg --icon app-icon.icns
This creates a macOS .dmg installer for MyApp. Similar commands work for Windows (--type exe) and Linux (--type deb or --type rpm).
Best Practices & Pitfalls
✅ Best Practices
- Use
jmodfor reusable libraries, not direct deployment - Always include
module-info.javato enforce strong encapsulation - Combine
jmod+jlink+jpackagefor full modular deployment - Test installers across OS platforms
❌ Pitfalls
- Using
.jmodas a runtime artifact (incorrect usage) - Forgetting to bundle native dependencies in
jmod - Overpacking installers with unnecessary modules → bloated installers
- Assuming
jpackagereplacesjlink(they complement each other)
What's New in Java Versions?
- Java 5–8 → N/A (Modules introduced in Java 9)
- Java 9 → Introduction of JPMS and
.jmodpackaging - Java 11 → Refinements in
jlinkandjmodworkflows - Java 14 → Introduction of
jpackageas an incubator tool - Java 16 →
jpackagestabilized and production-ready - Java 17 → Performance and usability improvements
- Java 21 → No significant updates across Java versions for this feature
Real-World Analogy
- jmod: Think of it as vacuum-sealed ingredients—well-structured, portable, and ready to be used in a recipe.
- jpackage: Think of it as a ready-to-serve meal complete with packaging, cutlery, and delivery to the end user.
Summary & Key Takeaways
jmodis used for creating reusable module artifacts.jpackageis used for distributing installable application bundles.- Together, they ensure clean modular workflows, from libraries to runtime images to end-user applications.
- Avoid misusing
jmodas a runtime deliverable. - Always test cross-platform installers before shipping.
FAQ: jmod and jpackage
1. What is the difference between JAR, jmod, and jpackage?
JARs are generic archives, .jmod is a module packaging format, and jpackage creates native installers.
2. Why shouldn’t I distribute jmod files directly?
They are intended for jlink and tooling, not as runtime deliverables.
3. Can jpackage include a custom runtime?
Yes, it bundles a jlink-generated runtime image automatically.
4. Does jpackage support icons and shortcuts?
Yes, it integrates OS-native features like icons, menus, and uninstallers.
5. When should I use jlink vs jpackage?
Use jlink to create custom runtimes, jpackage to ship installable applications.
6. Can I use jpackage for non-modular JARs?
Yes, but modular applications benefit the most.
7. Does jmod support native libraries?
Yes, you can include .so, .dll, or .dylib files inside a .jmod.
8. Can I migrate legacy fat JARs to jpackage?
Yes, but it’s best to modularize first for full benefits.
9. Does Spring Boot work with jpackage?
Yes, though Spring Boot apps may need tweaks for module-info compatibility.
10. Is jpackage cross-platform?
No, you must run jpackage on each target OS to build installers for that OS.