graalvm-native-image
giuseppe-trisciuoglio/developer-kit
Expert guidance for building GraalVM Native Image executables from Java applications.
What is graalvm-native-image?
This skill provides structured workflows for converting JVM applications to native binaries using GraalVM Native Image, optimizing cold start times and memory footprint. Use it when configuring native builds with Maven or Gradle, resolving reflection and resource issues, or implementing framework-specific native support for Spring Boot, Quarkus, and Micronaut.
- Analyze projects to detect build tools (Maven/Gradle), frameworks (Spring Boot, Quarkus, Micronaut), and native image challenges
- Configure Maven and Gradle with GraalVM Native Build Tools plugins and native profiles
- Generate and manage GraalVM metadata files (reflect-config.json, resource-config.json, proxy-config.json, serialization-config.json)
- Implement framework-specific AOT patterns including Spring Boot RuntimeHints and @RegisterReflectionForBinding
- Iteratively diagnose and fix native build failures by parsing error logs and applying targeted metadata updates
- Use the GraalVM tracing agent to collect reachability metadata for dynamic features
How to install graalvm-native-image
npx skills add https://github.com/giuseppe-trisciuoglio/developer-kit --skill graalvm-native-image- GraalVM JDK 17+ installed (Java 21+ recommended)
- Maven 3.8+ or Gradle 7.0+ with wrapper scripts available
- Existing Java application with pom.xml or build.gradle configuration
How to use graalvm-native-image
- 1.Analyze your project structure to detect the build tool (Maven or Gradle) and framework (Spring Boot, Quarkus, Micronaut, or plain Java)
- 2.Add the GraalVM Native Build Tools plugin to your build configuration (Maven native profile or Gradle native plugin)
- 3.For framework-specific projects, apply the appropriate AOT configuration (Spring Boot RuntimeHints, Quarkus/Micronaut defaults)
- 4.Execute the native build command (mvnw -Pnative package or gradlew nativeCompile) and capture the build log
- 5.Parse build errors to identify missing metadata (reflection, resources, proxies, serialization)
- 6.Update or create GraalVM metadata files in META-INF/native-image/ to register dynamic features
- 7.Re-run the native build and iterate until the executable compiles successfully
Use cases
- Converting a Spring Boot microservice to a native executable for serverless deployment with millisecond startup times
- Optimizing a CLI tool built with Quarkus to reduce memory footprint and startup latency
- Resolving ClassNotFoundException and NoSuchMethodException errors when building a native image of a reflection-heavy application using Jackson or Hibernate
- Configuring Maven native profile to build native executables while keeping the standard JVM build unchanged
- Registering dynamic proxies and serialization metadata for a Micronaut application targeting GraalVM Native Image
- Java developers migrating applications to serverless or containerized environments
- DevOps engineers optimizing cold start times for microservices
- Backend engineers building CLI tools or utilities requiring fast startup
- Teams using Spring Boot, Quarkus, or Micronaut who need native executable support
graalvm-native-image FAQ
GraalVM Native Image requires Java 17 or later; Java 21+ is recommended for best performance and compatibility.
Register reflected classes and methods in reflect-config.json or use framework-specific hints like Spring Boot's @RegisterReflectionForBinding and RuntimeHintsRegistrar.
The class is not registered in reflection metadata. Add it to reflect-config.json or use the GraalVM tracing agent to automatically collect metadata by running your application.
Yes. Spring Boot 3.x+ has built-in GraalVM support with AOT processing. Use the native profile and register reflection hints via RuntimeHintsRegistrar.
Maven uses a dedicated native profile with the native-maven-plugin; Gradle applies the org.graalvm.buildtools.native plugin. Both achieve the same result but use different configuration syntax.
Full instructions (SKILL.md)
Source of truth, from giuseppe-trisciuoglio/developer-kit.
name: graalvm-native-image description: Provides expert guidance for building GraalVM Native Image executables from Java applications. Use when converting JVM applications to native binaries, optimizing cold start times, reducing memory footprint, configuring native build tools for Maven or Gradle, resolving reflection and resource issues in native builds, or implementing framework-specific native support for Spring Boot, Quarkus, and Micronaut. Triggers include "graalvm native image", "native executable java", "java cold start optimization", "native build tools", "ahead of time compilation java", "reflection config graalvm", "native image build failure". allowed-tools: Read, Write, Edit, Bash, Glob, Grep
GraalVM Native Image for Java Applications
Expert skill for building high-performance native executables from Java applications using GraalVM Native Image, dramatically reducing startup time and memory consumption.
Overview
GraalVM Native Image compiles Java applications ahead-of-time (AOT) into standalone native executables. These executables start in milliseconds, require significantly less memory than JVM-based deployments, and are ideal for serverless functions, CLI tools, and microservices where fast startup and low resource usage are critical.
This skill provides a structured workflow to migrate JVM applications to native binaries, covering build tool configuration, framework-specific patterns, reflection metadata management, and an iterative approach to resolving native build failures.
When to Use
Use this skill when:
- Converting a JVM-based Java application to a GraalVM native executable
- Optimizing cold start times for serverless or containerized deployments
- Reducing memory footprint (RSS) of Java microservices
- Configuring Maven or Gradle with GraalVM Native Build Tools
- Resolving
ClassNotFoundException,NoSuchMethodException, or missing resource errors in native builds - Generating or editing
reflect-config.json,resource-config.json, or other GraalVM metadata files - Using the GraalVM tracing agent to collect reachability metadata
- Implementing
RuntimeHintsfor Spring Boot native support - Building native images with Quarkus or Micronaut
Instructions
1. Contextual Project Analysis
Before any configuration, analyze the project to determine the build tool, framework, and dependencies:
Detect the build tool:
# Check for Maven
if [ -f "pom.xml" ]; then
echo "Build tool: Maven"
# Check for Maven wrapper
[ -f "mvnw" ] && echo "Maven wrapper available"
fi
# Check for Gradle
if [ -f "build.gradle" ] || [ -f "build.gradle.kts" ]; then
echo "Build tool: Gradle"
[ -f "build.gradle.kts" ] && echo "Kotlin DSL"
[ -f "gradlew" ] && echo "Gradle wrapper available"
fi
Detect the framework by analyzing dependencies:
- Spring Boot: Look for
spring-boot-starter-*inpom.xmlorbuild.gradle - Quarkus: Look for
quarkus-*dependencies - Micronaut: Look for
micronaut-*dependencies - Plain Java: No framework dependencies detected
Check the Java version:
java -version 2>&1
# GraalVM Native Image requires Java 17+ (recommended: Java 21+)
Identify potential native image challenges:
- Reflection-heavy libraries (Jackson, Hibernate, JAXB)
- Dynamic proxy usage (JDK proxies, CGLIB)
- Resource bundles and classpath resources
- JNI or native library dependencies
- Serialization requirements
2. Build Tool Configuration
Configure the appropriate build tool plugin based on the detected environment.
For Maven projects, add a dedicated native profile to keep the standard build clean. See the Maven Native Profile Reference for full configuration.
Key Maven setup:
<profiles>
<profile>
<id>native</id>
<build>
<plugins>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<version>0.10.6</version>
<extensions>true</extensions>
<executions>
<execution>
<id>build-native</id>
<goals>
<goal>compile-no-fork</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
<configuration>
<imageName>${project.artifactId}</imageName>
<buildArgs>
<buildArg>--no-fallback</buildArg>
</buildArgs>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
Build with: ./mvnw -Pnative package
For Gradle projects, apply the org.graalvm.buildtools.native plugin. See the Gradle Native Plugin Reference for full configuration.
Key Gradle setup (Kotlin DSL):
plugins {
id("org.graalvm.buildtools.native") version "0.10.6"
}
graalvmNative {
binaries {
named("main") {
imageName.set(project.name)
buildArgs.add("--no-fallback")
}
}
}
Build with: ./gradlew nativeCompile
3. Framework-Specific Configuration
Each framework has its own AOT strategy. Apply the correct configuration based on the detected framework.
Spring Boot (3.x+): Spring Boot has built-in GraalVM support with AOT processing. See the Spring Boot Native Reference for patterns including RuntimeHints, @RegisterReflectionForBinding, and test support.
Key points:
- Use
spring-boot-starter-parent3.x+ which includes the native profile - Register reflection hints via
RuntimeHintsRegistrar - Run AOT processing with
process-aotgoal - Build with:
./mvnw -Pnative native:compileor./gradlew nativeCompile
Quarkus and Micronaut: These frameworks are designed native-first and require minimal additional configuration. See the Quarkus & Micronaut Reference.
4. GraalVM Reachability Metadata
Native Image uses a closed-world assumption — all code paths must be known at build time. Dynamic features like reflection, resources, and proxies require explicit metadata configuration.
Metadata files are placed in META-INF/native-image/<group.id>/<artifact.id>/:
| File | Purpose |
|---|---|
reachability-metadata.json | Unified metadata (reflection, resources, JNI, proxies, bundles, serialization) |
reflect-config.json | Legacy: Reflection registration |
resource-config.json | Legacy: Resource inclusion patterns |
proxy-config.json | Legacy: Dynamic proxy interfaces |
serialization-config.json | Legacy: Serialization registration |
jni-config.json | Legacy: JNI access registration |
See the Reflection & Resource Config Reference for complete format and examples.
5. The Iterative Fix Engine
Native image builds often fail due to missing metadata. Follow this iterative approach:
Step 1 — Execute the native build:
# Maven
./mvnw -Pnative package 2>&1 | tee native-build.log
# Gradle
./gradlew nativeCompile 2>&1 | tee native-build.log
Step 2 — Parse build errors and identify the root cause:
Common error patterns and their fixes:
| Error Pattern | Cause | Fix |
|---|---|---|
ClassNotFoundException: com.example.MyClass | Missing reflection metadata | Add to reflect-config.json or use @RegisterReflectionForBinding |
NoSuchMethodException | Method not registered for reflection | Add method to reflection config |
MissingResourceException | Resource not included in native image | Add to resource-config.json |
Proxy class not found | Dynamic proxy not registered | Add interface list to proxy-config.json |
UnsupportedFeatureException: Serialization | Missing serialization metadata | Add to serialization-config.json |
Step 3 — Apply fixes by updating the appropriate metadata file or using framework annotations.
Step 4 — Rebuild and verify. Repeat until the build succeeds.
Step 5 — If manual fixes are insufficient, use the GraalVM tracing agent to collect reachability metadata automatically. See the Tracing Agent Reference.
6. Validation and Benchmarking
Once the native build succeeds:
Verify the executable runs correctly:
# Run the native executable
./target/<app-name>
# For Spring Boot, verify the application context loads
curl http://localhost:8080/actuator/health
Measure startup time:
# Time the startup
time ./target/<app-name>
# For Spring Boot, check the startup log
./target/<app-name> 2>&1 | grep "Started .* in"
Measure memory footprint (RSS):
# On Linux
ps -o rss,vsz,comm -p $(pgrep <app-name>)
# On macOS
ps -o rss,vsz,comm -p $(pgrep <app-name>)
Compare with JVM baseline:
| Metric | JVM | Native | Improvement |
|---|---|---|---|
| Startup time | ~2-5s | ~50-200ms | 10-100x |
| Memory (RSS) | ~200-500MB | ~30-80MB | 3-10x |
| Binary size | JRE + JARs | Single binary | Simplified |
7. Docker Integration
Build minimal container images with native executables:
# Multi-stage build
FROM ghcr.io/graalvm/native-image-community:21 AS builder
WORKDIR /app
COPY . .
RUN ./mvnw -Pnative package -DskipTests
# Minimal runtime image
FROM debian:bookworm-slim
COPY --from=builder /app/target/<app-name> /app/<app-name>
EXPOSE 8080
ENTRYPOINT ["/app/<app-name>"]
For Spring Boot applications, use paketobuildpacks/builder-jammy-tiny with Cloud Native Buildpacks:
./mvnw -Pnative spring-boot:build-image
Best Practices
- Start with the tracing agent on complex projects to generate an initial metadata baseline
- Use the
nativeprofile to keep native-specific config separate from standard builds - Prefer
--no-fallbackto ensure a true native build (no JVM fallback) - Test with
nativeTestto run JUnit tests in native mode - Use GraalVM Reachability Metadata Repository for third-party library metadata
- Minimize reflection — prefer constructor injection and compile-time DI where possible
- Include resource patterns explicitly rather than relying on classpath scanning
- Profile before and after — always measure startup and memory improvements
- Use Java 21+ for the best GraalVM compatibility and performance
- Keep GraalVM and Native Build Tools versions aligned
Examples
Example 1: Adding Native Support to a Spring Boot Maven Project
Scenario: You have a Spring Boot 3.x REST API and want to compile it to a native executable.
Step 1 — Add the native profile to pom.xml:
<profiles>
<profile>
<id>native</id>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>process-aot</id>
<goals>
<goal>process-aot</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</profile>
</profiles>
Step 2 — Register reflection hints for DTOs:
@RestController
@RegisterReflectionForBinding({UserDto.class, OrderDto.class})
public class UserController {
@GetMapping("/users/{id}")
public UserDto getUser(@PathVariable Long id) {
return userService.findById(id);
}
}
Step 3 — Build and run:
./mvnw -Pnative native:compile
./target/myapp
# Started MyApplication in 0.089 seconds
Example 2: Resolving a Reflection Error in Native Build
Scenario: Native build fails with ClassNotFoundException for a Jackson-serialized DTO.
Error output:
com.oracle.svm.core.jdk.UnsupportedFeatureError:
Reflection registration missing for class com.example.dto.PaymentResponse
Fix — Add to src/main/resources/META-INF/native-image/reachability-metadata.json:
{
"reflection": [
{
"type": "com.example.dto.PaymentResponse",
"allDeclaredConstructors": true,
"allDeclaredMethods": true,
"allDeclaredFields": true
}
]
}
Or use the Spring Boot annotation approach:
@RegisterReflectionForBinding(PaymentResponse.class)
@Service
public class PaymentService { /* ... */ }
Example 3: Using the Tracing Agent for a Complex Project
Scenario: A project with many third-party libraries needs comprehensive reachability metadata.
# 1. Build the JAR
./mvnw package -DskipTests
# 2. Run with the tracing agent
java -agentlib:native-image-agent=config-output-dir=src/main/resources/META-INF/native-image \
-jar target/myapp.jar
# 3. Exercise all endpoints
curl http://localhost:8080/api/users
curl -X POST http://localhost:8080/api/orders -H 'Content-Type: application/json' -d '{"item":"test"}'
curl http://localhost:8080/actuator/health
# 4. Stop the application (Ctrl+C), then build native
./mvnw -Pnative native:compile
# 5. Verify
./target/myapp
Constraints and Warnings
Critical Constraints
- GraalVM Native Image requires Java 17+ (Java 21+ recommended for best compatibility)
- Closed-world assumption: All code paths must be known at build time — dynamic class loading, runtime bytecode generation, and
MethodHandles.Lookupmay not work - Build time and memory: Native compilation is resource-intensive — expect 2-10 minutes and 4-8 GB RAM for typical projects
- Not all libraries are compatible: Libraries relying heavily on reflection, dynamic proxies, or CGLIB may require extensive metadata configuration
- AOT profiles are fixed at build time: Spring Boot
@Profileand@ConditionalOnPropertyare evaluated during AOT processing, not at runtime
Common Pitfalls
- Forgetting
--no-fallback: Without this flag, the build may silently produce a JVM fallback image instead of a true native executable - Incomplete tracing agent coverage: The agent only captures code paths exercised during the run — ensure all features are tested
- Version mismatches: Keep GraalVM JDK, Native Build Tools plugin, and framework versions aligned to avoid incompatibilities
- Classpath differences: The classpath at AOT/build time must match runtime — adding/removing JARs after native compilation causes failures
Security Considerations
- Native executables are harder to decompile than JARs, but are not tamper-proof
- Ensure secrets are not embedded in the native image at build time
- Use environment variables or external config for sensitive data
Troubleshooting
| Issue | Solution |
|---|---|
| Build runs out of memory | Increase build memory: -J-Xmx8g in buildArgs |
| Build takes too long | Use build cache, reduce classpath, enable quick build mode for dev |
| Application crashes at runtime | Missing reflection/resource metadata — run tracing agent |
| Spring Boot context fails to load | Check @Conditional beans and profile-dependent config |
| Third-party library not compatible | Check GraalVM Reachability Metadata repo or add manual hints |
Related skills
More from giuseppe-trisciuoglio/developer-kit and the wider catalog.

knowledge-graph
Persistent JSON knowledge graph for caching codebase analysis and validating task dependencies.

langchain4j-ai-services-patterns
Build type-safe, declarative AI services in Java with LangChain4j using interface patterns and annotations.

langchain4j-mcp-server-patterns
LangChain4j patterns for building and integrating MCP servers with tool calling and secure agent workflows.

langchain4j-rag-implementation-patterns
RAG implementation patterns with LangChain4j for Java: document ingestion, embeddings, and semantic search.

langchain4j-spring-boot-integration
Integrate LangChain4j with Spring Boot using declarative AI Services, auto-configuration, and dependency injection.

langchain4j-testing-strategies
Unit, integration, and mock testing patterns for LangChain4j Java AI services and RAG workflows.