skip to content

How do you configure the output name and pass extra `native-image` flags using the `graalvmNative` DSL?

level: middleimportance: should knowfreq 45%

answer

  1. graalvmNative { binaries { named("main") } }
  2. imageName.set(...) renames binary
  3. buildArgs.add(...) = raw native-image flags
  4. quickBuild = -Ob, fallback = --no-fallback
  5. lazy Property/ListProperty, args are additive

basics

~10 s

Inside graalvmNative { binaries { named("main") { ... } } } you set imageName.set("my-app") for the executable's name and add native-image flags with buildArgs.add("--verbose").

solid answer

~40 s

The `graalvmNative` extension exposes named binaries — `main` for the app image and `test` for the test image. On each you configure GraalVM `Property`/`ListProperty` values: `imageName` sets the output file name, `mainClass` overrides the entry point, `buildArgs.add(...)` appends raw flags passed straight to `native-image` (e.g. `-H:+ReportExceptionStackTraces`, `--initialize-at-build-time=...`), and convenience toggles like `verbose`, `debug`, `quickBuild`, and `fallback` map to well-known flags. Because these are Gradle lazy `Property` types you use `.set(...)` / `.add(...)`. `buildArgs` is the escape hatch for any flag the DSL doesn't model directly. The plugin merges its own defaults (Spring's AOT-generated args, `--no-fallback`) with what you add, so your `buildArgs` are additive, not a full replacement.

code

kotlin · 11 lines
kotlin
graalvmNative {
    binaries {
        named("main") {
            imageName.set("katajob-api")
            buildArgs.add("-H:+ReportExceptionStackTraces")
            buildArgs.add("--initialize-at-build-time=com.katajob.Constants")
            quickBuild.set(true)   // -Ob for fast local builds only
            fallback.set(false)    // --no-fallback (fail loudly)
        }
    }
}

go deeper

for a junior

Know that imageName names the binary and buildArgs passes extra flags.

for a middle

Explain named main/test binaries, lazy Property/ListProperty usage, and common toggles (verbose/debug/quickBuild/fallback).

for a senior

Discuss that buildArgs is additive over Spring's AOT args and the risks of --initialize-at-build-time.

for a principal

Weigh quickBuild vs optimized builds in a pipeline and how to parameterize buildArgs across environments.

## The extension shape ```kotlin graalvmNative { binaries { named("main") { imageName.set("katajob-api") mainClass.set("com.katajob.ApplicationKt") buildArgs.add("--initialize-at-build-time=org.example.Constants") buildArgs.add("-H:+ReportExceptionStackTraces") verbose.set(true) debug.set(false) quickBuild.set(true) // -Ob: faster, less-optimized build fallback.set(false) // --no-fallback } named("test") { buildArgs.add("--verbose") } } metadataRepository { enabled.set(true) } toolchainDetection.set(false) } ``` ## Named binaries The plugin defines two binaries by default: **`main`** (used by `nativeCompile`/`nativeRun`) and **`test`** (used by `nativeTest`). You configure them via `binaries { named("main") { … } }` in Kotlin DSL, or `binaries { main { … } test { … } }` in Groovy. Each binary is an independent set of options. ## Key options - **`imageName`** — the file name of the produced executable (default is derived from the project/main class). Setting it renames the output binary. - **`mainClass`** — the entry point; usually inferred from Spring Boot, but overridable. - **`buildArgs`** — a `ListProperty<String>` of raw arguments forwarded verbatim to `native-image`. This is the general-purpose knob for anything the DSL doesn't wrap, e.g. `--enable-url-protocols=http,https`, `--initialize-at-build-time`, `-H:...` host options, `-R:...` runtime options. - **`verbose`** — echoes the `native-image` command line. - **`debug`** — includes debug info (`-g`) for tools like gdb. - **`quickBuild`** — passes `-Ob` for a faster build with fewer optimizations (great for local iteration, not for production). - **`fallback`** — controls `--no-fallback`; the plugin disables the fallback image by default so failures are loud rather than silently producing a JVM-backed 'fallback' binary. - **`richOutput`**, **`jvmArgs`**, **`runtimeArgs`**, **`sharedLibrary`**, **`configurationFileDirectories`** — additional less-common options. ## Lazy properties Everything is Gradle's lazy configuration API: `imageName` is a `Property<String>` (use `.set(...)`), `buildArgs` is a `ListProperty<String>` (use `.add(...)`/`.addAll(...)`). You cannot assign with `=` in Kotlin DSL except via the `.set` form (Kotlin DSL supports `imageName = ...` only where an assignment convention exists — prefer `.set` to be safe). ## Additive, not replacing Your `buildArgs` are appended to the plugin's and Spring's own generated arguments (AOT reachability config, `--no-fallback`, metadata repo directories). You are extending the command line, not overriding it — a frequent misconception. ## Passing args from the command line You can also pass one-off args without editing the build: `./gradlew nativeCompile --pgo-instrument` style options exist for specific features, and arbitrary extra args can be injected via project properties bound to `buildArgs` in your build script. ## Gotchas - `imageName` sets the binary name only; it does not change the Gradle task name. - Overusing `--initialize-at-build-time` on classes with runtime state can bake stale values into the image — prefer letting Spring's hints and the reachability metadata handle it. - `quickBuild`/`-Ob` images are noticeably slower at runtime — never ship them to production.

  • If you set `buildArgs`, do you lose Spring's AOT-generated native-image arguments?
    No. `buildArgs` is a ListProperty that is appended to the plugin's and Spring's own generated arguments. You are extending the native-image command line, not replacing it.
  • What does `quickBuild` do and when should you avoid it?
    It passes `-Ob` for a much faster, lightly optimized build — ideal for local iteration. Avoid it for production images because runtime performance is significantly worse.

saying these in an interview costs you the question

  • Claiming `buildArgs` replaces all default/AOT-generated flags
  • Thinking `imageName` changes the Gradle task name rather than the output binary name
  • Believing you must edit native-image's own config files instead of using the DSL

context