Java Spring Boot Dockerfile Template
Java Spring Boot applications have historically produced large Docker images because of the JVM's runtime size and the fat JAR packaging that bundles all dependencies. Modern Spring Boot (3.x) and Docker best practices have substantially changed this picture through layered JARs, custom JRE images built with jlink, and multi-stage builds that can produce images as small as 100–150MB compared to the 400–500MB fat JARs of a few years ago.
The layered JAR feature introduced in Spring Boot 2.3 is the most impactful optimization for Spring Boot Docker images. A Spring Boot fat JAR packages your application code, Spring framework classes, and all third-party dependencies into a single file. Docker treats this entire JAR as a single layer — any code change forces a complete re-download of all dependencies. Layered JARs split the fat JAR into four distinct layers: spring-boot-loader (rarely changes), snapshot-dependencies (changes occasionally), dependencies (changes when you add/remove libraries), and application (changes every build). When these layers are added to the Docker image separately, only the changed layers are re-pushed and re-pulled.
The multi-stage Dockerfile for Spring Boot uses an Eclipse Temurin or Corretto JDK image for the build stage and a corresponding JRE (not JDK) image for the runtime stage. The JDK contains the compiler and development tools; the JRE contains only what is needed to run Java applications. Switching from JDK to JRE in the runtime stage removes approximately 100–150MB from the final image.
JVM memory settings must be configured for containerized environments. By default, the JVM calculates its heap size based on the host machine's memory, not the container's memory limit. This causes the JVM to request more memory than Kubernetes or ECS has allocated, triggering OOMKill. Use -XX:+UseContainerSupport (enabled by default in JDK 11+) and -XX:MaxRAMPercentage=75 to configure the heap as a fraction of the container's memory limit.
Spring Boot Actuator provides health check endpoints (/actuator/health) that should be referenced in your Docker HEALTHCHECK instruction. This integrates cleanly with Kubernetes readiness and liveness probes and gives your orchestrator accurate information about application health rather than just process health.
Template Preview
{"language":"java","javaVersion":"21","framework":"spring-boot","useLayeredJar":true,"multiStage":true,"nonRootUser":true,"healthCheck":true,"jvmMemoryFlags":true}Customize this template with your own details using the free generator:
▸Open in GeneratorFAQ
- Should I use Amazon Corretto, Eclipse Temurin, or OpenJDK as my base image?
- All three are production-quality OpenJDK distributions. Eclipse Temurin (the successor to AdoptOpenJDK) is the most widely used and has the most frequent security updates. Amazon Corretto is preferred in AWS environments because Amazon tests it extensively in their own services. Microsoft's distro is good if you use Azure. All are free. Avoid the official java Docker Hub images — they are deprecated and unmaintained.
- How do I enable Spring Boot layered JARs?
- Spring Boot layered JARs are enabled by default in Spring Boot 2.3+. To extract layers in your Dockerfile build stage, use: java -Djarmode=layertools -jar application.jar extract. This creates four directories (spring-boot-loader, snapshot-dependencies, dependencies, application) that you then COPY into the runtime stage in order from slowest-changing to fastest-changing, maximizing Docker layer cache reuse.
- What JVM flags should I set for a containerized Spring Boot app?
- Essential flags: -XX:+UseContainerSupport to read memory limits from cgroups instead of host memory; -XX:MaxRAMPercentage=75 to cap heap at 75% of container memory (leaving room for off-heap, metaspace, and thread stacks); -XX:+UseG1GC for most workloads (default in Java 9+); -Djava.security.egd=file:/dev/./urandom to speed up startup in environments with limited entropy.