skip to content

Walk through configuring bootBuildImage for a native build in both Gradle and Maven, including choosing the builder and publishing the image.

level: seniorimportance: should knowfreq 38%

answer

  1. Gradle: environment/imageName/builder/publish + docker{publishRegistry}
  2. Maven: <image><env>BP_NATIVE_IMAGE</env> + -Pnative profile
  3. tiny builder = smallest, distroless run image for native
  4. BP_NATIVE_IMAGE_BUILD_ARGUMENTS passes flags to native-image
  5. publish=true pushes straight to registry

basics

~20 s

In Gradle configure the bootBuildImage task: set environment BP_NATIVE_IMAGE=true, an imageName, optionally a builder, and publish/docker credentials. In Maven, use spring-boot-maven-plugin's <image> config with <env><BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE></env>, or the built-in native profile, plus <publish> and <docker> settings.

solid answer

~30 s

Gradle: configure the `bootBuildImage` task — `environment.put("BP_NATIVE_IMAGE","true")` (or just apply the GraalVM plugin), `imageName.set(...)`, optionally `builder.set("paketobuildpacks/builder-jammy-tiny")`, and for publishing `publish.set(true)` with `docker { publishRegistry { username/password/url } }`. Maven: the `spring-boot-maven-plugin` `<image>` block carries `<name>`, `<builder>`, and `<env>` (where you put `BP_NATIVE_IMAGE`), while `<docker><publishRegistry>` holds credentials; the Spring Boot parent also ships a `native` profile that sets the env var, so `mvn spring-boot:build-image -Pnative` works. For native, the **tiny** builder gives the smallest, most locked-down run image; the base builder is more compatible if you need extra OS packages. Publishing pushes straight to the registry when `publish=true`.

code

kotlin · 14 lines
kotlin
tasks.named<org.springframework.boot.gradle.tasks.bundling.BootBuildImage>("bootBuildImage") {
    imageName.set("registry.example.com/acme/myapp:${'$'}{project.version}")
    builder.set("paketobuildpacks/builder-jammy-tiny")
    environment.put("BP_NATIVE_IMAGE", "true")
    environment.put("BP_NATIVE_IMAGE_BUILD_ARGUMENTS", "--verbose")
    publish.set(true)
    docker {
        publishRegistry {
            username.set(System.getenv("REG_USER"))
            password.set(System.getenv("REG_TOKEN"))
            url.set("https://registry.example.com")
        }
    }
}

go deeper

for a junior

Know there is an image config block with an env entry and an image name.

for a middle

Set BP_NATIVE_IMAGE, imageName, and know the Maven native profile shortcut.

for a senior

Configure builder choice, publishing, credentials, and forward native-image args.

for a principal

Standardize builder tags for GraalVM version control and wire publish/credentials into CI securely.

**Gradle configuration.** The `bootBuildImage` task type is `org.springframework.boot.gradle.tasks.bundling.BootBuildImage`. Key properties: - `imageName` — the tag, e.g. `docker.io/acme/myapp:1.0.0`. Defaults to `docker.io/library/${project.name}:${version}`. - `environment` — a `Map<String,String>` of `BP_*` variables sent to the buildpack; put `BP_NATIVE_IMAGE=true` here (or rely on the GraalVM plugin auto-enable). Other useful ones: `BP_JVM_VERSION` (irrelevant for native), `BP_NATIVE_IMAGE_BUILD_ARGUMENTS` to pass extra flags straight to `native-image`. - `builder` — the CNB builder image to use, e.g. `paketobuildpacks/builder-jammy-tiny`. `runImage` overrides the base for the final image. - `publish` — `true` to push the finished image to a registry instead of loading it into the local daemon. - `docker { builderRegistry {...}; publishRegistry {...} }` — credentials for pulling the builder and pushing the result. **Maven configuration.** The `spring-boot-maven-plugin` exposes the same knobs under an `<image>` element: ```xml <configuration> <image> <name>docker.io/acme/myapp:1.0.0</name> <builder>paketobuildpacks/builder-jammy-tiny</builder> <env><BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE></env> <publish>true</publish> </image> <docker> <publishRegistry> <username>${REG_USER}</username> <password>${REG_TOKEN}</password> </publishRegistry> </docker> </configuration> ``` Run with `mvn spring-boot:build-image`. Spring Boot's parent POM also defines a **`native` profile** that flips on native compilation, so `mvn -Pnative spring-boot:build-image` is the idiomatic shortcut and you may not need to set `BP_NATIVE_IMAGE` yourself. **Builder choice.** Paketo offers builders like `builder-jammy-tiny`, `builder-jammy-base`, and `builder-jammy-full`. For **native images** the **tiny** builder is the usual recommendation: its run image is distroless-like (no shell, minimal packages), yielding the smallest attack surface and image size — which pairs naturally with a self-contained native binary that has few OS dependencies. Use **base** if your app or native-image args need extra shared libraries or a shell. The builder pins the GraalVM version, so switching GraalVM = switching/upgrading the builder tag. **Publishing.** With `publish=true` the plugin exports the image directly to the registry named in `imageName`/`<name>` using the `publishRegistry` credentials — handy in CI so you skip a separate `docker push`. Without it, the image is loaded into the local daemon. **Passing native-image flags.** Use `BP_NATIVE_IMAGE_BUILD_ARGUMENTS` (e.g. `--verbose`, `-H:+ReportExceptionStackTraces`, `-march=...`) to influence the in-container `native-image` invocation without a local GraalVM. **Gotchas.** (1) Credentials must be for the **publishRegistry** to push and the **builderRegistry** if your builder is private. (2) `imageName` must be a fully-qualified reference to publish to a non-DockerHub registry. (3) The builder architecture determines the output architecture — no cross-arch. (4) Native builds need generous memory allocated to the Docker daemon or the buildpack fails mid-compile.

  • Why is the tiny builder often preferred for native images?
    Its run image is minimal and distroless-like — no shell, few packages — giving the smallest image and attack surface. Native executables are largely self-contained, so they rarely need the extra OS packages that the base/full builders provide.
  • How do you pass an extra flag to the underlying native-image command?
    Set the BP_NATIVE_IMAGE_BUILD_ARGUMENTS buildpack env var (e.g. via environment.put in Gradle or <env> in Maven); the buildpack forwards it to the in-container native-image invocation.

saying these in an interview costs you the question

  • Putting registry credentials only under builderRegistry when trying to publish
  • Assuming -Pnative and BP_NATIVE_IMAGE are both mandatory together
  • Thinking the full builder is required for native (tiny is the lean default)

context