π₯ Why Multi-stage Docker Builds Matter
When deploying Spring Boot applications, using a traditional single-stage Dockerfile results in large, insecure images containing unnecessary build tools like Maven or Gradle. Multi-stage builds help you:
- πͺΆ Reduce image size
- π Improve security by excluding build dependencies
- π¦ Separate build and runtime concerns
This guide walks you through creating a clean, production-ready Docker image using multi-stage builds for your Spring Boot app.

π¦ Project Setup
We’ll continue using the same Spring Boot app with package:com.kscodes.springboot.containers
You can follow this structure:
springboot-app/
βββ src/
βββ pom.xml
βββ Dockerfile
βββ .dockerignore
βοΈ Multi-stage Dockerfile
Hereβs a Dockerfile using two stages: builder and runtime.
# -------- Stage 1: Build the JAR --------
FROM eclipse-temurin:21-jdk AS builder
WORKDIR /app
# Copy everything and build
COPY . .
RUN ./mvnw clean package -DskipTests
# -------- Stage 2: Slim runtime --------
FROM eclipse-temurin:21-jre
WORKDIR /app
# Copy only the JAR from the builder image
COPY --from=builder /app/target/*.jar app.jar
# Expose port and run the app
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
This results in a clean image with only the Spring Boot JAR file β no Maven, no source files, no unnecessary layers.
π .dockerignore
To avoid bloating your Docker context:
target/
.git/
.idea/
*.iml
*.md
π¨ Build & Run
docker build -t springboot-multistage .
docker run -p 8080:8080 springboot-multistage
Open http://localhost:8080 and verify your app is running.
π Compare Image Sizes
Letβs compare using the command below:
docker images | grep springboot
Typical results:
| Image Type | Size |
|---|---|
| Single-stage | 480 MB+ |
| Multi-stage | ~150 MB |
Multi-stage builds often shrink the image by 60β70%.
π‘οΈ Security Benefits
Multi-stage builds also:
- Remove build tools (Maven, Gradle)
- Eliminate vulnerable dependencies
- Reduce attack surface
Great for passing container vulnerability scans (Snyk, Trivy, etc.)
β‘ Layer Caching Tip (Optional)
For faster rebuilds, separate dependency copy:
COPY pom.xml .
COPY src/main/resources/ /app/resources
RUN ./mvnw dependency:go-offline
COPY src/ /app/src
RUN ./mvnw clean package -DskipTests
This allows Docker to cache dependencies if your code changes, speeding up builds.
β Best Practices
| Practice | Why It Matters |
|---|---|
| Use Alpine base images | Smaller, faster |
Use jre in runtime image | Lower memory footprint |
| Tag images semantically | Avoid latest in production |
| Donβt hardcode secrets | Use environment variables instead |
π Summary
In this guide, you learned how to create a multi-stage Docker build for Spring Boot thatβs optimized, secure, and production-ready. By separating the build and runtime environments, you drastically reduce image size and attack surface β setting a strong foundation for deployment to Kubernetes or cloud platforms. Hope this helps.