How do you configure Jib for a Spring Boot application, and what should you watch out for compared to a plain JVM app?
answer
- apply Boot + Jib together
- Jib ignores the fat bootJar — uses exploded layout
- set mainClass = ...ApplicationKt
- ports 8080, MaxRAMPercentage
- vs bootBuildImage (buildpacks, daemon)
basics
~10 sApply Jib alongside the Spring Boot plugin, point container.mainClass at your @SpringBootApplication class, expose the server port, and set jvmFlags. Jib containerizes the exploded app, not the repackaged fat JAR.
solid answer
~40 sFor Spring Boot you apply both the Boot plugin and Jib. Key difference: Jib does **not** use Boot's repackaged fat JAR — it containerizes the compiled classes, resources, and resolved dependencies directly, which actually plays well with Boot since you keep Jib's clean layering instead of one big executable JAR. You set `container.mainClass` to your `@SpringBootApplication` class (or the Kotlin `AppKt`), `container.ports` to the server port (`8080`), and `container.jvmFlags` for memory (`-XX:MaxRAMPercentage=75`). Watch out for: making sure the `bootJar`/`jar` task config does not confuse main-class detection, and that any Boot loader expectations are dropped — Jib launches `java -cp ... YourApplication` directly. Container-aware JVM flags and a non-root `container.user` are the usual hardening additions.
code
kotlin · 11 linesjib {
from { image = "eclipse-temurin:21-jre" }
to { image = "ghcr.io/acme/orders:${'$'}{project.version}" }
container {
mainClass = "com.acme.orders.OrdersApplicationKt"
ports = listOf("8080")
jvmFlags = listOf("-XX:MaxRAMPercentage=75")
environment = mapOf("SPRING_PROFILES_ACTIVE" to "prod")
user = "1000:1000"
}
}go deeper
Know you apply Jib next to the Boot plugin and set mainClass and the port.
Explain Jib uses the exploded layout (not the fat JAR) and configure ports/jvmFlags/profiles.
Discuss container-aware JVM flags, non-root user, and the trade-offs vs bootBuildImage.
Decide org-wide between Jib and buildpacks weighing determinism, daemon-free CI, and runtime governance.
## Applying both plugins ```kotlin plugins { id("org.springframework.boot") version "3.3.2" id("io.spring.dependency-management") version "1.1.6" id("com.google.cloud.tools.jib") version "3.4.3" kotlin("jvm") version "2.0.0" } ``` ## What Jib does NOT do The Spring Boot plugin's `bootJar` produces a **repackaged executable fat JAR** with a nested-JAR launcher (`org.springframework.boot.loader`). **Jib ignores that.** It takes the *exploded* output — your compiled classes, `src/main/resources`, and the resolved dependency JARs — and lays them out in separate layers, launching with a plain `java -cp ... MainClass`. So you get Jib's incremental layering rather than one monolithic Boot JAR, and you do **not** rely on the Boot loader at runtime. ## Configuration ```kotlin jib { from { image = "eclipse-temurin:21-jre" } to { image = "ghcr.io/acme/orders" tags = setOf("latest", project.version.toString()) } container { mainClass = "com.acme.orders.OrdersApplicationKt" ports = listOf("8080") jvmFlags = listOf("-XX:MaxRAMPercentage=75", "-XX:+UseG1GC") user = "1000:1000" environment = mapOf("SPRING_PROFILES_ACTIVE" to "prod") } } ``` ## Things to watch - **mainClass detection.** With Boot, the `@SpringBootApplication` class is the entry point. If you wrote a Kotlin `main` in `OrdersApplication.kt`, the JVM class is `OrdersApplicationKt`. Set it explicitly to avoid ambiguous detection. - **No Boot loader features.** Anything depending on the nested-JAR layout (e.g., reading resources via the loader, `PropertiesLauncher` tricks) won't apply; classpath is flat. - **Container-aware memory.** Prefer `-XX:MaxRAMPercentage` over fixed `-Xmx` so the JVM respects cgroup limits. - **Port + profile metadata** belong in `container.ports` and `container.environment`, not a Dockerfile. - **DevTools / test scopes** should not leak into the image; they normally don't because Jib uses runtime classpath. ## Why teams pick Jib over bootBuildImage Boot's own `bootBuildImage` uses Cloud Native Buildpacks (and needs a Docker daemon). Jib is daemon-free and gives explicit, fast layering. The trade-off is buildpacks add more automatic OS/runtime management; Jib is leaner and more deterministic.
- Does Jib package Spring Boot's repackaged fat JAR?No. Jib uses the exploded classes, resources, and dependency JARs in separate layers and launches with a plain java -cp, ignoring the Boot loader fat JAR.
- Why prefer -XX:MaxRAMPercentage over -Xmx in the container?MaxRAMPercentage makes the JVM size its heap relative to the container's cgroup memory limit, so the image works correctly across different memory allocations.
- How does Jib differ from Spring Boot's bootBuildImage?bootBuildImage uses Cloud Native Buildpacks and needs a Docker daemon; Jib is daemon-free with explicit deterministic layering.
saying these in an interview costs you the question
- Saying Jib wraps the Boot fat JAR as one layer.
- Using fixed -Xmx that ignores container memory limits.
- Confusing Jib with bootBuildImage/buildpacks.