Native image with GraalVM — what is AOT compilation? What… — Cracked Java
// Spring Framework & Spring Boot · Spring Boot 3 Features & Modern Stack
SeniorTheoryBig Tech

Native image with GraalVM — what is AOT compilation? What are the limits?

A GraalVM native image is your Spring app compiled ahead-of-time into a standalone native executable — no JVM at runtime. The win is startup in tens of milliseconds and a fraction of the memory; the cost is a closed-world model that fights everything Spring traditionally does at runtime.

What AOT compilation means here

Normally the JVM loads bytecode and JIT-compiles hot paths while running. GraalVM's native-image tool instead does ahead-of-time compilation: it statically analyzes the entire reachable program at build time and produces a native binary. This is a closed-world assumption — anything not provable as reachable at build time simply isn't included.

Spring adds its own AOT processing step (Spring AOT, run by the Boot plugin) that executes before GraalVM. It starts your ApplicationContext at build time, evaluates conditions and auto-configuration, and emits generated @Bean factory code plus RuntimeHints describing the reflection, resources, and proxies the app needs.

@Configuration
@ImportRuntimeHints(MyApp.Hints.class)
class MyApp {
    static class Hints implements RuntimeHintsRegistrar {
        public void registerHints(RuntimeHints hints, ClassLoader cl) {
            hints.reflection().registerType(SomeDto.class,
                MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);
        }
    }
}
// Or, for serialization/binding targets:
@RegisterReflectionForBinding(SomeDto.class)

The limits — what breaks without hints

GraalVM can't see code reached only via runtime mechanisms, so these need explicit hints:

  • Reflection — fields/methods/constructors looked up by name (JSON binding, JPA).
  • Dynamic proxies — JDK proxies (@Transactional, @Cacheable, repository interfaces, @HttpExchange).
  • Runtime classpath scanning and resource loading (classpath*: patterns, .properties).

Spring's AOT generates most of these hints for you. Where it can't infer them — your own reflection, a non-Spring library — you supply them via RuntimeHints / @RegisterReflectionForBinding, or run the GraalVM tracing agent to record what's actually used.

Mark your status