Generated banner for Java Add Graalvm Native Image Support
Generated logo for Java Add Graalvm Native Image Support

Java Add Graalvm Native Image Support

GitHubOfficialFirst committed by jduboisDistributed by GitHub

  • Skill
  • Tool integration
  • Software development
  • MIT
  • No issues found

From the author

GraalVM Native Image skill for Spring Boot, Micronaut and plain Java: detects the build tool and framework, adds native image support, builds the executable, analyzes errors, and iterates until the native build succeeds and the binary runs correctly. For Quarkus projects it only dispatches to the quarkus-native-and-container skill.
— the description by jdubois

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

This skill provides a structured, iterative approach to enabling GraalVM Native Image support for Java applications. It identifies the project's build tool and framework, configures the necessary plugins, and guides the user through the build-test-fix cycle required to produce a functional native executable. It handles framework-specific requirements for Spring Boot and Micronaut while delegating Quarkus projects to dedicated tooling.

What it does

  • Detects build tools (Maven/Gradle) and frameworks (Spring Boot, Micronaut, plain Java).
  • Configures native build plugins and profiles for GraalVM compatibility.
  • Provides iterative troubleshooting steps for build and runtime errors.
  • Assists in managing reachability metadata and reflection configuration.
  • Verifies native executables through testing and execution.
  • Delegates Quarkus-specific native builds to the appropriate specialized skill.

When to use it

  • When you need to compile a Java application into a standalone native executable.
  • When you encounter build errors while attempting to generate a native image.
  • When you need to configure reflection or resource access for native compilation.
  • When you are migrating a Spring Boot or Micronaut application to GraalVM.

Advantages

  • Standardizes the native build process across different Java frameworks.
  • Reduces manual configuration effort for native build plugins.
  • Provides a clear, iterative path for resolving complex native image compatibility issues.
  • Ensures JVM baseline stability before attempting native builds.

Usage examples

“Add GraalVM native image support to my Spring Boot project.”
The agent analyzes the project's build files, adds the required native plugins, and provides the command to initiate the native build.
“My native build is failing with a reflection error in Micronaut.”
The agent identifies the missing reflection configuration and suggests adding the appropriate @Introspected or @TypeHint annotations.

Install

  1. Download the skill as a ZIP:

    https://autogineer.com/agent-skills/github/java-add-graalvm-native-image-support/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip java-add-graalvm-native-image-support.zip -d .agents/skills

Documentation by jdubois

GraalVM Native Image Support

Single source of truth for adding GraalVM Native Image to a Java project, whatever the framework. Work iteratively: configure, build, read the error, fix, rebuild, until the native build succeeds and the executable runs correctly.

Detail lives in references/; load only what the project needs:

TopicFile
Maven / Gradle native plugin setupreferences/build-tools.md
Reachability metadata and tracing agentreferences/reachability-metadata.md
Common build/runtime errors and fixesreferences/troubleshooting.md
Spring Boot (AOT, -Pnative, nativeCompile, build-image)references/spring-boot.md
Quarkusquarkus-native-and-container skill (hand off); short pointer in references/quarkus.md
Micronautreferences/micronaut.md

Step 1: Analyze the project

  1. Build tool: pom.xml (Maven) or build.gradle / build.gradle.kts (Gradle). Prefer the wrapper (./mvnw, ./gradlew) when present.

  2. Framework, from dependencies/plugins:

    • Spring Boot: spring-boot-starter-parent, spring-boot-maven-plugin, or org.springframework.boot Gradle plugin

    • Quarkus: io.quarkus BOM/plugin or quarkus-* dependencies

    • Micronaut: io.micronaut parent/plugin or micronaut-* dependencies

    • otherwise plain Java

  3. Existing native configuration: native-build-tools plugin, META-INF/native-image/, native profile, application.properties native keys.

  4. Toolchain: run java -version and native-image --version. Local native compilation needs a GraalVM JDK (with native-image) as the JDK used for the build. Container or buildpack builds (Spring Boot buildpacks via bootBuildImage/spring-boot:build-image, Quarkus container builds) compile inside a container and need no local GraalVM, only a container runtime. Check the project's Java level against the installed GraalVM version.

If the framework is Quarkus, stop here and hand off to the quarkus-native-and-container skill. Container builds there need no local GraalVM.

Scope and JVM baseline

  • Adding native support does not authorize a JDK, framework, library, build-tool, or wrapper upgrade. Preserve the existing BOM/parent-managed versions and test conventions; ask before changing versions to solve native compatibility.

  • Run the project's existing JVM build and tests before editing. Record pre-existing failures rather than weakening checks to hide them. Keep the JVM packaging/run path working alongside native support.

  • After any approved dependency or framework change, rerun that JVM baseline before continuing with native builds. Verify the same relevant behavior on both JVM and native paths.

  • Ask before creating or changing CI workflows, adding native CI jobs, or changing runner resources. Suggest commands separately if CI changes were not requested.

Step 2: Get a GraalVM toolchain

  • Oracle GraalVM (free under the GraalVM Free Terms and Conditions) and GraalVM Community Edition builds provide native-image. Use a release matching the project's Java version (for example, GraalVM for JDK 21 or newer; Spring Boot 3.x/4.x need a Java 17+ baseline, see the Spring reference).

  • Install with SDKMAN (sdk list java, then sdk install java <identifier> using an identifier from that list), a vendor download, or a CI action such as graalvm/setup-graalvm. Pick the version from the vendor's current download page rather than hard-coding one.

  • Linux needs a C toolchain and zlib headers (build-essential, zlib1g-dev); macOS needs Xcode command line tools; Windows needs Visual Studio Build Tools. Check the current GraalVM "Native Image prerequisites" page.

Step 3: Add native support

Per framework:

  • Spring Boot: with Maven, spring-boot-starter-parent only manages the native plugins' versions and configuration in its native profile, so declare native-maven-plugin and spring-boot-maven-plugin in <build><plugins> if missing (no versions needed); with Gradle, apply org.graalvm.buildtools.native next to org.springframework.boot; a custom parent needs the plugin added by hand. Do not duplicate configuration the parent already provides. See references/spring-boot.md.

  • Quarkus: hand off to the quarkus-native-and-container skill.

  • Micronaut: built in via the Micronaut build plugins. See references/micronaut.md.

  • Plain Java (or any project without a framework plugin): add the GraalVM Native Build Tools plugin. See references/build-tools.md. Resolve the plugin version at run time from Maven Central (org.graalvm.buildtools:native-maven-plugin) or the Gradle Plugin Portal (org.graalvm.buildtools.native) and pin it in the build file; do not copy a version from memory.

Step 4: Build

SetupCommand
Plain Maven./mvnw -Pnative native:compile
Plain Gradle./gradlew nativeCompile
Spring Boot Maven./mvnw -Pnative native:compile (or spring-boot:build-image for a container)
Spring Boot Gradle./gradlew nativeCompile (or bootBuildImage)
Micronaut Maven./mvnw package -Dpackaging=native-image
Micronaut Gradle./gradlew nativeCompile

Native builds are slow and memory hungry (several GB of RAM). Capture the full output to inspect it.

Step 5: Iterate until the build succeeds

  1. Read the first real error, not the final summary.

  2. Match it against references/troubleshooting.md.

  3. Apply the smallest fix, in this order of preference:

    1. Check whether a compatible library/framework version has built-in native support (see the reachability metadata repository). Propose the upgrade; apply it only with user approval and rerun the JVM baseline. If declined, try metadata or framework hints compatible with the current versions.

    2. Use the framework's own mechanism (Spring RuntimeHints, Quarkus @RegisterForReflection, Micronaut @Introspected).

    3. Collect metadata with the tracing agent (see references/reachability-metadata.md).

    4. Hand-write metadata under src/main/resources/META-INF/native-image/<groupId>/<artifactId>/.

    5. Adjust initialization (--initialize-at-build-time / --initialize-at-run-time) only for specific classes.

  4. Rebuild. Repeat until the build completes with no errors.

Step 6: Verify the executable

A successful build is not enough: many problems only appear at runtime.

  • Run the binary and exercise the main paths (HTTP endpoints, DB access, serialization, resource loading, scheduled jobs).

  • Run the native tests where the framework supports them (native:test, nativeTest, Quarkus @QuarkusIntegrationTest).

  • Compare startup time and memory against the JVM run only if the user asks for it.

  • Report the exact commands run, whether the build and the run succeeded, and any remaining warnings.

Pitfalls

  • Recommend a native build and native test run in CI with an explicit GraalVM version; add or change CI only with user consent.

  • Mockito's default inline mock maker does not work on native image (Mockito 5.0.0 release notes); use the subclass mock maker for native tests.

  • Do not leave --report-unsupported-elements-at-runtime or verbose flags in production builds unless justified.

References

Upstream sources (read before upgrading GraalVM or native config)

Fetch the page for the target version; prefer it over this skill when they conflict.

Files

references/reachability-metadata.md

Reachability metadata and the tracing agent

Native Image only includes what it can see statically. Anything reached dynamically (reflection, resources, JNI, dynamic proxies, serialization) must be described by reachability metadata.

Where metadata lives

src/main/resources/META-INF/native-image/<groupId>/<artifactId>/ in your project (the <groupId>/<artifactId> subfolder avoids clashes between jars). Two formats exist:

  • Legacy per-feature files: reflect-config.json, resource-config.json, jni-config.json, proxy-config.json, serialization-config.json.

  • Unified reachability-metadata.json (introduced in GraalVM for JDK 23 and used by newer releases). The unified format is preferred for new metadata and supports newer capabilities, but Native Image still discovers legacy files under META-INF/native-image, so do not discard valid existing configuration. Check the GraalVM documentation for your version and prefer regenerating metadata with the tracing agent of the toolchain you use.

Libraries often publish metadata themselves, and the community GraalVM reachability metadata repository covers many popular ones. The Native Build Tools plugin pulls it automatically when enabled (metadataRepository in Gradle, default for recent plugin versions in Maven). Check existing metadata first; if an upgrade would help, propose it for user approval and rerun the JVM baseline after the change. Otherwise collect or write metadata for the current version.

Tracing agent

Run the app on the JVM with the agent while exercising every code path, and the agent writes the metadata.

Direct:

java -agentlib:native-image-agent=config-output-dir=src/main/resources/META-INF/native-image/<groupId>/<artifactId> -jar target/app.jar

Via the build tool (preferred):

./mvnw -Pnative -Dagent=true -DskipNativeTests=true test # collect test-stage metadata on the JVM
./gradlew -Pagent test                      # agent during tests, Gradle
./gradlew -Pagent run
./gradlew metadataCopy --task test --dir src/main/resources/META-INF/native-image/<groupId>/<artifactId>

The Maven example assumes the plain-Java native profile in build-tools.md, which also binds native:test to the test phase. Check the actual project's profile bindings: Spring Boot uses a separate nativeTest profile (see spring-boot.md). Use -DskipNativeTests=true for metadata collection so JVM tests still execute with the tracing agent, without compiling or running native test binaries. Do not use -DskipTests or -Dmaven.test.skip: those skip the JVM tests needed to exercise the agent.

The Maven agent writes to target/native/agent-output/{test,main}. Review the files for noise, then configure metadata copying inside the Native Build Tools plugin so the approved output survives clean and is included in the native build:

<configuration>
  <!-- Keep any existing Native Build Tools configuration here. -->
  <agent>
    <metadataCopy>
      <!-- For the JVM test command above, skip the main stage that was not run. -->
      <disabledStages>
        <stage>main</stage>
      </disabledStages>
      <merge>true</merge>
      <outputDirectory>${project.basedir}/src/main/resources/META-INF/native-image/${project.groupId}/${project.artifactId}</outputDirectory>
    </metadataCopy>
  </agent>
</configuration>

After reviewing the test-stage output, persist it with:

./mvnw -Pnative -Dagent=true native:metadata-copy

If you collected only the application (main) stage, disable test instead; configure disabledStages for every stage you did not collect. merge=true merges with existing metadata when the destination has a complete metadata set (unified reachability-metadata.json or all four legacy files); otherwise merge or reconcile existing partial files manually before copying, so valid metadata is not discarded. Run native tests afterwards with the project's appropriate profile and without -DskipNativeTests=true; the metadata-collection run is not evidence that native tests passed.

For a manual application run, configure the exec-maven-plugin execution described in the Native Build Tools Maven agent guide, then run it with:

./mvnw -Pnative -Dagent=true -DskipTests -DskipNativeBuild=true package exec:exec@java-agent

Copy the collected main stage as above, disabling the uncollected test stage.

See the Native Build Tools "Agent Support" page for the exact setup for your plugin version.

Tips:

  • Exercise every endpoint, serialization path and resource load; unexercised paths are not captured.

  • Review the generated files and delete noise (test-only classes).

  • Merge repeated runs with native-image-configure or the agent's merge mode (config-merge-dir=).

  • Re-run the agent after changing dependencies.

Hand-written examples (legacy format)

Reflection (reflect-config.json):

[
  {
    "name": "com.example.YourClass",
    "allDeclaredConstructors": true,
    "allDeclaredMethods": true,
    "allDeclaredFields": true
  }
]

Resources (resource-config.json):

{
  "resources": {
    "includes": [
      {"pattern": "\\Qapplication.properties\\E"},
      {"pattern": ".*\\.ya?ml"}
    ]
  }
}

JNI (jni-config.json):

[
  {
    "name": "com.example.NativeClass",
    "methods": [
      {"name": "nativeMethod", "parameterTypes": ["java.lang.String"]}
    ]
  }
]

Dynamic proxies (proxy-config.json):

[
  ["com.example.Interface1", "com.example.Interface2"]
]

Frameworks offer typed alternatives (Spring RuntimeHints, Quarkus @RegisterForReflection, Micronaut @Introspected); prefer them to raw JSON in framework projects.

Requirements and compatibility

Written for: GitHub Copilot

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Security

No issues found by our static scan· No issues found

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

First committed by
GitHub avatar of jduboisjdubois
Publisher
GitHub (Official)
Distributed by
GitHub
Source
github/awesome-copilot · skills/java-add-graalvm-native-image-support · commit 797337f
Licence
MIT License (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced
Contributors
jdubois

AutoGineer is not affiliated with or endorsed by jdubois or GitHub.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download java-add-graalvm-native-image-support.zip