← Back to Questions
Docker

How to reduce Docker image size?

Learn How to reduce Docker image size? with simple explanations, real-time examples, interview tips and practical use cases.

How to Reduce Docker Image Size?

Reducing Docker image size is an important production optimization technique in DevOps, Kubernetes, microservices, CI/CD pipelines, and cloud-native deployments. Smaller Docker images are faster to build, faster to push, faster to pull, easier to scan, cheaper to store, and safer to run in production.

Simple Answer: Docker image size can be reduced by using lightweight base images, multi-stage builds, .dockerignore, removing unnecessary files, avoiding build tools in runtime images, minimizing layers, and scanning/removing unused dependencies.

Why Docker Image Size Matters

In production systems, image size directly impacts deployment speed and cloud cost. When Kubernetes or Docker pulls an image from a registry, a larger image takes more time and bandwidth.

Large Image Problem:

Large Image
    |
    v
Slow Push to Registry
    |
    v
Slow Pull in Kubernetes Node
    |
    v
Slow Pod Startup
    |
    v
Slow Scaling During Traffic Spike
    

This becomes critical during high-traffic events like Black Friday in the USA, Boxing Day sales in the UK, or Diwali traffic in India.

Real Production Example

Assume a payment microservice image size is 1.2 GB.

Normal Traffic:
Payment Service -> 2 containers

Heavy Traffic:
Payment Service -> 20 containers

If image size is 1.2 GB:
20 pods may take longer to start

If image size is 250 MB:
20 pods start much faster
    

Smaller images improve auto-scaling speed and reduce deployment risk.

Best Ways to Reduce Docker Image Size

  1. Use multi-stage builds
  2. Use lightweight base images
  3. Use .dockerignore
  4. Do not copy unnecessary files
  5. Use JRE instead of JDK for Java runtime
  6. Remove package manager cache
  7. Combine RUN commands carefully
  8. Avoid installing unnecessary tools
  9. Use dependency caching properly
  10. Use distroless images for high-security production

1. Use Multi-Stage Docker Builds

Multi-stage build is the most effective way to reduce Docker image size. It separates the build environment from the runtime environment.

Bad Dockerfile Without Multi-Stage Build

FROM maven:3.9.6-eclipse-temurin-17

WORKDIR /app

COPY . .

RUN mvn clean package -DskipTests

EXPOSE 8080

CMD ["java", "-jar", "target/app.jar"]
    

This final image contains Maven, source code, build cache, test files, and the JDK.

Good Dockerfile With Multi-Stage Build

FROM maven:3.9.6-eclipse-temurin-17 AS build

WORKDIR /app

COPY pom.xml .

RUN mvn dependency:go-offline -B

COPY src ./src

RUN mvn clean package -DskipTests

FROM eclipse-temurin:17-jre-jammy

WORKDIR /app

COPY --from=build /app/target/*.jar app.jar

EXPOSE 8080

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

The final image contains only Java runtime and the application JAR.

2. Use Lightweight Base Images

Base image selection has a huge impact on final image size.

Heavy Base Image

FROM ubuntu:22.04
    

Better Java Runtime Image

FROM eclipse-temurin:17-jre-jammy
    

Even Smaller Option

FROM eclipse-temurin:17-jre-alpine
    

Alpine images are smaller, but always test compatibility because some libraries behave differently with Alpine’s musl libc compared to glibc-based images.

3. Use JRE Instead of JDK in Runtime

For Java Spring Boot applications, the final production image usually does not need Maven or full JDK.

Build Stage:
Maven + JDK

Runtime Stage:
JRE only
    

This significantly reduces image size and attack surface.

4. Use .dockerignore

A .dockerignore file prevents unnecessary files from being sent to Docker build context.

Recommended .dockerignore

.git
.gitignore
.idea
.vscode
target
logs
*.log
*.tmp
.env
node_modules
README.md
Dockerfile
docker-compose.yml
*.sql
    

Without .dockerignore, Docker may copy unnecessary files into the build context, increasing build time and sometimes image size.

5. Do Not Copy the Entire Project Blindly

Bad Example

COPY . .
    

This can copy logs, local configs, SQL dumps, temporary files, Git history, and IDE files.

Better Example

COPY pom.xml .
COPY src ./src
    

Copy only what is required to build the application.

6. Remove Package Manager Cache

If you install packages, remove package cache in the same layer.

Bad Example

RUN apt-get update
RUN apt-get install -y curl
    

Good Example

RUN apt-get update && apt-get install -y --no-install-recommends curl \
    && rm -rf /var/lib/apt/lists/*
    

This prevents package lists and cache files from remaining in the final image.

7. Avoid Unnecessary Tools in Runtime Image

Production runtime images should not contain tools that are only useful for debugging or building.

Avoid in runtime image:

- Maven
- Gradle
- Git
- curl unless required
- wget unless required
- build-essential
- compilers
- test tools
    

Keep the runtime image minimal.

8. Combine RUN Commands Carefully

Docker images are layer-based. Each RUN instruction creates a new layer.

Bad Example

RUN apt-get update
RUN apt-get install -y curl
RUN rm -rf /var/lib/apt/lists/*
    

Good Example

RUN apt-get update && apt-get install -y --no-install-recommends curl \
    && rm -rf /var/lib/apt/lists/*
    

Cleaning must happen in the same RUN layer to reduce final image size.

9. Use Distroless Images

Distroless images contain only the application and runtime dependencies. They do not include shell, package manager, or unnecessary OS tools.

Example

FROM gcr.io/distroless/java17-debian12

COPY app.jar /app/app.jar

ENTRYPOINT ["java", "-jar", "/app/app.jar"]
    

Distroless images are smaller and more secure, but debugging is harder because they do not include shell tools.

10. Use Spring Boot Layered JARs

Spring Boot supports layered JARs, which can improve Docker layer caching.

java -Djarmode=layertools -jar app.jar extract
    

This separates dependencies, snapshot dependencies, resources, and application classes into different layers.

Spring Boot Layered Dockerfile Example

FROM maven:3.9.6-eclipse-temurin-17 AS build

WORKDIR /app

COPY pom.xml .

RUN mvn dependency:go-offline -B

COPY src ./src

RUN mvn clean package -DskipTests

FROM eclipse-temurin:17-jre-jammy AS extract

WORKDIR /app

COPY --from=build /app/target/*.jar app.jar

RUN java -Djarmode=layertools -jar app.jar extract

FROM eclipse-temurin:17-jre-jammy

WORKDIR /app

COPY --from=extract /app/dependencies/ ./
COPY --from=extract /app/spring-boot-loader/ ./
COPY --from=extract /app/snapshot-dependencies/ ./
COPY --from=extract /app/application/ ./

EXPOSE 8080

ENTRYPOINT ["java", "org.springframework.boot.loader.launch.JarLauncher"]
    

11. Use Specific Image Tags

Avoid latest because it is unpredictable.

Bad

FROM openjdk:latest
    

Good

FROM eclipse-temurin:17-jre-jammy
    

Stable base image versions improve reproducibility and rollback safety.

12. Analyze Image Layers

Use tools to identify which layer is increasing image size.

docker history image-name

docker image inspect image-name
    

You can also use tools like dive to inspect image layers.

13. Clean Build Artifacts

Avoid keeping build outputs, temporary folders, and package caches inside final runtime images.

Remove:

- /tmp files
- package manager cache
- build cache
- test reports
- source code
- unused dependencies
    

14. Use External Storage for Files

Do not bake uploads, logs, SQL dumps, or user-generated files into images.

Bad

COPY uploads /app/uploads
COPY logs /app/logs
COPY backup.sql /app/backup.sql
    

Good

Uploads -> S3 / volume
Logs -> stdout / Loki / ELK / CloudWatch
Database backups -> external backup storage
    

15. Use Minimal Node.js Build for Frontend

For React, Angular, or Vue applications, build with Node.js but serve with Nginx.

FROM node:20 AS build

WORKDIR /app

COPY package*.json ./

RUN npm ci

COPY . .

RUN npm run build

FROM nginx:alpine

COPY --from=build /app/dist /usr/share/nginx/html

EXPOSE 80
    

The final image does not contain Node.js or source code.

Image Size Reduction Strategy Table

Technique Impact
Multi-stage build Very high
Lightweight base image High
.dockerignore High
JRE instead of JDK High
Remove package cache Medium
Distroless image High
Layered Spring Boot JAR Medium to high

Bad Dockerfile Example

FROM openjdk:latest

WORKDIR /app

COPY . .

RUN apt-get update
RUN apt-get install -y curl git vim

RUN mvn clean package -DskipTests

EXPOSE 8080

CMD ["java", "-jar", "target/app.jar"]
    

Why This Image Becomes Large

  • Uses heavy and unpredictable base image
  • Copies entire project
  • Installs unnecessary tools
  • Does not clean package cache
  • Includes build tools in final image
  • Does not use multi-stage build

Optimized Production Dockerfile

FROM maven:3.9.6-eclipse-temurin-17 AS build

WORKDIR /app

COPY pom.xml .

RUN mvn dependency:go-offline -B

COPY src ./src

RUN mvn clean package -DskipTests

FROM eclipse-temurin:17-jre-jammy

WORKDIR /app

RUN groupadd -r appuser && useradd -r -g appuser appuser

COPY --from=build /app/target/*.jar app.jar

RUN chown -R appuser:appuser /app

USER appuser

EXPOSE 8080

ENTRYPOINT ["java", "-XX:+UseContainerSupport", "-XX:MaxRAMPercentage=75.0", "-jar", "app.jar"]
    

Production Checklist to Reduce Docker Image Size

[ ] Use multi-stage build
[ ] Use lightweight runtime image
[ ] Use JRE instead of JDK
[ ] Add .dockerignore
[ ] Copy only required files
[ ] Avoid latest tag
[ ] Remove package manager cache
[ ] Avoid unnecessary runtime tools
[ ] Use external storage for uploads/logs
[ ] Analyze image layers
[ ] Scan final image
    

Interview Answer

Docker image size can be reduced by using multi-stage builds, lightweight base images, .dockerignore, JRE instead of JDK for Java applications, removing package manager cache, avoiding unnecessary tools, and copying only required files.

In production, smaller images improve Kubernetes pod startup time, reduce network transfer, lower cloud storage cost, improve security scanning speed, and make deployments faster and more reliable.

Useful Internal Links

Final Conclusion

Reducing Docker image size is a critical production best practice. It improves deployment speed, scaling speed, security, cost efficiency, and CI/CD performance.

The best approach is to use multi-stage builds, lightweight runtime images, .dockerignore, minimal dependencies, proper caching, and external storage for runtime data. These practices make Docker images production-ready for Kubernetes, AWS ECS, Docker Compose, and modern microservices platforms.

Why this Docker question is important?

This interview question helps candidates understand real-time backend development concepts, practical problem solving, coding fundamentals, system design basics and production-ready application behavior.

Practice this question carefully for Java backend roles, Spring Boot developer interviews, microservices interviews, company interviews and full-stack developer preparation.

About the Author

Naresh Kumar is a Senior Java Backend Engineer with experience building enterprise applications using Java, Spring Boot, Microservices, Docker, Kubernetes and Cloud technologies.