Phase 5 · Professional DevelopmentModule 39~36 min read

Packaging, Deployment & Distribution

Package and ship Java apps with JARs, jlink, jpackage, and Docker.

What you'll learn

Code isn't done until it runs where users can reach it. This module covers the last mile: packaging your application, configuring it for different environments, containerizing with Docker, and deploying and monitoring it in production.

By the end you'll be able to:

  • Package an app as a runnable (fat) JAR
  • Build slim runtimes and native installers with jlink and jpackage
  • Configure apps per environment without rebuilding
  • Containerize with Docker
  • Understand deployment and production monitoring

JARs & fat JARs

You met JARs in Module 11 — a bundle of your compiled classes. But your app also depends on libraries. A fat JAR (or "uber JAR") packs your code and all its dependencies into a single executable file, so deployment is just "copy one JAR and run it." Build tools produce these for you:

Terminal
# A build tool bundles your code + all dependencies into one
# runnable "fat" (uber) JAR — nothing else to install but a JRE.
mvn package

java -jar target/app.jar    # runs anywhere Java is installed

jlink & jpackage

For more control, the JDK offers two tools. jlink builds a custom, minimal Java runtime containing only the modules your app uses — smaller images, faster startup. jpackage goes further and creates a native installer (.exe, .dmg, .deb) that bundles a runtime, so users can install your app without having Java at all.

Configuration & environments

The same application must run in different environments — your laptop, a test server, production — each with different database URLs, ports, and keys. The rule: build once, configure per environment. Read settings from environment variables or external config files, never hardcode them:

Config.java
// Read configuration from the environment, not hardcoded values —
// the SAME build then runs in dev, staging, and production.
String dbUrl = System.getenv("DATABASE_URL");

int port = Integer.parseInt(
    System.getProperty("server.port", "8080"));   // 8080 is the default

Note

This is why secrets belong in the environment (Module 36) and why the same artifact promotes cleanly from staging to production — only the configuration changes, not the code.

Docker

Docker packages your app and its entire environment — the JRE, OS libraries, config — into a portable container image that runs identically everywhere. This finally kills "works on my machine." A short Dockerfile describes how to build the image:

Dockerfile
# Start from an image that already has Java 21
FROM eclipse-temurin:21-jre

WORKDIR /app
COPY target/app.jar app.jar

EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

Tip

Use a JRE base image (not the full JDK) to keep images small, and a multi-stage build (build with the JDK, then copy just the JAR into a slim JRE image) for the leanest result. Containers are the standard unit of deployment in the cloud and Kubernetes.

Deploying & monitoring

With a JAR or container in hand, deployment means running it on a server or cloud platform (AWS, Google Cloud, Azure) — increasingly automated by the CI/CD pipeline from Module 32. But shipping isn't the end:

From code to production
Build→Test→Package (JAR)→Containerize→Deploy→Monitor

In production you need observability: centralised logs (Module 30), metrics (request rates, latency, error rates, memory), and alerts that page you when something breaks. Java tools like Micrometer and Java Flight Recorder, paired with dashboards (Grafana), keep you informed about your live system.

Recap & quick check

Key takeaways

  • A fat/uber JAR bundles your code plus all dependencies into one runnable file.
  • jlink builds a minimal custom runtime; jpackage builds native installers.
  • Build once, configure per environment — read settings from env vars/config, never hardcode.
  • Docker packages the app plus its environment into a portable container image.
  • Production needs observability: centralised logs, metrics, and alerts.

Quick check

1. What is a fat (uber) JAR?

2. How should environment-specific settings (DB URL, port) be provided?

3. What does Docker package into a container image?

4. What does jpackage produce?

5. Why is monitoring important after deployment?

Excellent — you've completed Phase 5 and can take software all the way to production. One phase remains: Phase 6 — the Capstone Projects that turn knowledge into a portfolio.