Packaging & Deployment
Fat JARs, jlink and jpackage, Docker for Java apps, and CI/CD concepts.
On this page
Your app works on your machine - now get it running reliably everywhere else. Packaging and deployment turn your code into something you can ship and run in production, consistently and repeatably.
Packaging: bundling your app
The starting point is a JAR (Java ARchive) - your compiled classes zipped together. For a runnable app, you build a fat JAR (also called uber or executable JAR) that bundles all dependencies so it runs standalone:
./gradlew bootJar # or: mvn package (with Spring Boot)
java -jar app.jar # runs anywhere with a JVMSpring Boot produces a fat JAR with an embedded web server - one file to run your whole application.
Custom runtimes with jlink and jpackage
Modern Java tools can shrink and package further:
jlinkbuilds a minimal custom JVM containing only the modules your app uses - smaller and faster to ship.jpackagecreates a native installer (.exe,.dmg,.deb) so users install your app like any other program.
Containers: Docker
Before standardized shipping containers, loading a ship meant hand-packing mismatched crates - slow and unreliable. Standard containers made cargo portable: any crane, any ship, any port. Docker does this for software - it packages your app and its entire environment into a standard container that runs identically on a laptop, a server, or the cloud.
A Dockerfile describes how to build the image:
FROM eclipse-temurin:21-jre # a JVM base image
COPY app.jar /app.jar # add your fat JAR
ENTRYPOINT ["java", "-jar", "/app.jar"]docker build -t my-shop . # build the image
docker run -p 8080:8080 my-shop # run itWhy containers won
Containers solve 'it works on my machine' - the app carries its exact environment with it, so it behaves the same everywhere. They start fast, isolate cleanly, and are the standard unit of deployment in modern cloud platforms like Kubernetes.
CI/CD: automating the pipeline
You shouldn't build and deploy by hand. CI/CD automates it:
- Continuous Integration (CI) - on every push, automatically build the code and run all tests. Broken changes are caught immediately.
- Continuous Delivery/Deployment (CD) - automatically package and deploy code that passes, to staging or production.
Instead of hand-inspecting and shipping each product, an assembly line automatically tests every item and moves the good ones onward. CI/CD is that line for code: every change is built, tested, and - if it passes - shipped, with no manual, error-prone steps.
Tools like GitHub Actions, GitLab CI, and Jenkins run these pipelines. A typical flow: push → build → test → build container → deploy.
Environments
Code moves through stages before reaching users:
| Environment | Purpose |
|---|---|
| Development | Your machine, while coding |
| Staging | A production-like rehearsal for final testing |
| Production | The live system real users touch |
Configuration (database URLs, secrets) differs per environment - supplied through environment variables, never hard-coded.
Keep secrets out of your code and images
Database passwords, API keys, and tokens must come from the environment or a secrets manager - never committed to Git or baked into a container image. Leaked credentials are one of the most common (and costly) security incidents.
Quick check
What problem do Docker containers primarily solve?
Key takeaways
- Package apps as JARs; a fat/executable JAR bundles dependencies to run standalone.
- jlink builds a minimal custom JVM; jpackage creates native installers.
- Docker containers package your app plus its environment so it runs identically everywhere.
- CI automatically builds and tests every change; CD automatically packages and deploys passing code.
- Code flows through development, staging, and production environments with per-environment config.
- Never commit secrets - supply them via environment variables or a secrets manager.
One final, crucial topic: keeping your applications - and your users - safe.