Introduction
When I joined PayPay, one of the first things I tried to understand was how our services were containerized.
A common exercise when joining a new backend team is to look at the Dockerfiles used across services as they often reveal interesting patterns:
Which base images are used
Whether the builds are optimized
If multi-stage builds are implemented
Opportunities for reducing image size or improving caching
So naturally, I went looking for the Dockerfile.
But to my surpriseโฆ I couldn't find one.
After digging a bit deeper, I realized something interesting. The project wasnโt using a Dockerfile at all. Instead, it was using Jib.
๐ฆ Enter Jib
Imagine shipping a Java microservice where changing a single line of code doesnโt force your CI pipeline to rebuild a massive container image.
Thatโs exactly what Jib enables.
Jib is an open-source container image builder for Java applications that:
Eliminates the need for a Dockerfile
Does not require a Docker daemon
Integrates directly with Maven and Gradle
Instead of packaging your application as a single fat layer, Jib understands Java project structure and splits your application into optimized layers:
Runtime (base image)
Dependencies
Resources
Application classes
Because of this layered structure, when you change only your application code, only the top layer is rebuilt and pushed.
The result?
โก Faster builds
๐งฑ Better caching
๐ Simpler CI pipelines
๐ง Less Dockerfile maintenance
In this post, we'll explore how Jib works, when to use it, and how it compares to traditional Dockerfiles.
๐ What is Jib?
If you build Java applications and ship containers, youโve probably written Dockerfiles like this:
FROM eclipse-temurin:17-jre
WORKDIR /app
COPY target/app.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
It works.
But itโs not optimized for Java.
This is where Jib changes the game.
๐งฑ The Problem With Traditional Docker Builds
Before Jib, containerizing Java apps required:
Writing and maintaining Dockerfiles
Installing Docker everywhere (including CI)
Packaging fat JARs
Rebuilding full images for small code changes
Manually optimizing layers
Even a small code change could invalidate caching and rebuild everything.
Thatโs inefficient.
๐ง How Jib Works
Jib builds container images by splitting your app into logical layers:
Base Image (JRE)
Dependencies
Resources
Application classes
This means:
If dependencies donโt change โ layer reused
If only code changes โ only top layer rebuilt
This drastically improves CI speed.
๐ ๏ธ Getting Started with Jib
Maven Setup
Add this to your pom.xml:
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>3.4.0</version>
<configuration>
<to>
<image>ghcr.io/yourorg/yourapp</image>
</to>
</configuration>
</plugin>
Build & push:
mvn compile jib:build
Gradle Setup
plugins {
id("com.google.cloud.tools.jib") version "3.4.0"
}
jib {
to {
image = "ghcr.io/yourorg/yourapp"
}
}
Build:
./gradlew jib
โ๏ธ Dockerfile vs Jib - Which Is Better?
This is the real question.
The answer depends on some of the use cases.
โ When Jib Is Better
1. Standard Java Microservices
Spring Boot
Micronaut
Quarkus
Plain Maven/Gradle apps
Jib integrates directly with your build system.
2. Faster CI/CD Pipelines
Jib:
Does not require a Docker daemon
Builds incremental layers
Pushes smaller diffs
Produces reproducible builds
If CI time matters, Jib usually wins.
3. Developer Simplicity
No Dockerfile. No manual layering. Less DevOps friction.
๐๏ธ When Dockerfile Is Better
1. OS-Level Customization
If you need:
apt-get installNative libraries
Custom shell scripts
Jib does not support arbitrary RUN commands.
Dockerfile wins here.
2. Polyglot Applications
If your container includes:
Node + Java
Python + Java
Multiple build tools
Custom entrypoints
Dockerfile provides full flexibility.
3. Complex Multi-Stage Builds
Example:
Compile native binaries
Build frontend assets
Run security scans during build
Copy artifacts between stages
Dockerfile is more powerful here.
๐ Side-by-Side Comparison
Feature |
Jib |
Dockerfile |
|---|---|---|
Requires Docker daemon |
โ No |
โ Yes |
Requires Dockerfile |
โ No |
โ Yes |
OS Customization |
โ Limited |
โ Full |
Java Layer Optimization |
โ Automatic |
โ Manual |
CI/CD Simplicity |
โ High |
โ ๏ธ Medium |
Multi-language builds |
โ No |
โ Yes |
Learning Curve |
Low |
Medium |
๐ฏ Real-World Scenarios
Scenario A: 20 Spring Boot Microservices
Kubernetes
GitHub Actions
CI cost matters
๐ Jib is usually the better choice.
Scenario B: Enterprise App With Native Dependencies
Custom Alpine base image
OS packages
Hardening scripts
Multi-stage builds
๐ Dockerfile is better.
Scenario C: Small Startup Team
Java-only stack
No DevOps team
Want fast pipelines
๐ Jib simplifies everything.
๐ฌ Performance Insight
Because Jib separates dependencies and classes:
Code-only changes rebuild in seconds
Docker layer cache invalidation is minimized
CI builds are more predictable
In large microservice ecosystems, this adds up significantly.
๐ Closing Thoughts
Jib is optimized for:
Java developer productivity.
Dockerfile is optimized for:
Infrastructure control.
If you build modern Java microservices โ Start with Jib.
If you need deep OS-level control โ Use Dockerfile.
Containerization doesnโt have to be complicated. If your stack is Java-centric and you value speed, reproducibility, and developer autonomy, then Jib is one of the smart tools you can adopt today.
Top comments (0)