Dockerizing a Java App the Right Way in 2026
Multi-stage builds, layered JARs, distroless images, and the JVM flags that make containers behave. A production Dockerfile you can actually copy.

A naive FROM openjdk Dockerfile produces a 600MB image that rebuilds from
scratch on every code change and ignores the container’s memory limits. Let’s
fix all three problems.
Use multi-stage builds
Build with a full JDK, run with a slim JRE. The build tools never ship to production.
# ---- build stage ----
FROM eclipse-temurin:21-jdk AS build
WORKDIR /app
COPY . .
RUN ./mvnw -q -DskipTests package
# ---- runtime stage ----
FROM eclipse-temurin:21-jre AS runtime
WORKDIR /app
COPY --from=build /app/target/app.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
Layer your JAR for fast rebuilds
Spring Boot can split a JAR into layers (dependencies change rarely, your code
changes constantly). Ordering COPY from least- to most-volatile means Docker
reuses cached layers:
FROM eclipse-temurin:21-jre AS runtime
WORKDIR /app
COPY --from=build /app/target/dependencies/ ./
COPY --from=build /app/target/spring-boot-loader/ ./
COPY --from=build /app/target/snapshot-dependencies/ ./
COPY --from=build /app/target/application/ ./
ENTRYPOINT ["java", "org.springframework.boot.loader.launch.JarLauncher"]
Respect container memory limits
Modern JVMs are container-aware, but be explicit. Set a percentage of the
container’s memory rather than a fixed -Xmx:
ENV JAVA_OPTS="-XX:MaxRAMPercentage=75 -XX:+UseG1GC"
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
Without
MaxRAMPercentage, a JVM in a 512MB container can still try to grab a heap sized for the host machine — and get OOM-killed.
Go distroless for the smallest, safest image
Distroless images contain only your app and the JRE — no shell, no package manager, a tiny attack surface:
FROM gcr.io/distroless/java21-debian12
COPY --from=build /app/target/app.jar /app.jar
ENTRYPOINT ["/app.jar"]
The checklist
- ✅ Multi-stage build (JDK to build, JRE/distroless to run)
- ✅ Layered copy for cache-friendly rebuilds
- ✅
MaxRAMPercentageinstead of fixed heap - ✅ Non-root user (distroless runs as nonroot by default)
- ✅ A real
.dockerignore(don’t shiptarget/,.git,node_modules)
Do these five things and your image drops from ~600MB to ~180MB, rebuilds in seconds, and behaves predictably under a memory limit.
Related articles

Building a Full SaaS Application with NestJS, React, PostgreSQL and Docker
A step-by-step, production-grade guide: architecture, multi-tenant database design, JWT auth, NestJS APIs, a React frontend, Docker, CI/CD with GitHub Actions, scalability, and the best practices that hold up in production.

Anthropic Joins Frontier's Carbon-Removal Coalition — While Fighting an Export-Control Fire
On June 17, 2026, Anthropic became the first dedicated AI company to join Frontier, the advance-market-commitment coalition for permanent carbon removal, helping push its pledges to $1.8B. It happened in the middle of a high-profile U.S. export-control dispute over Claude Fable 5 and Mythos 5. Here's both stories.

Tim Cook: Apple Price Hikes Are 'Unavoidable' as AI Drains the Memory Market
In a WSJ interview published June 17, 2026, Apple CEO Tim Cook confirmed price increases are coming, blaming a 'hundred-year flood' in memory and storage chip costs driven by AI data-center demand. Here's why DRAM and NAND prices spiked, what could get pricier, and the context behind the move.
Have a project or an idea?
We don't just write about software — we build it. Tell us what you're working on and we'll get back within 1–2 business days.