Ahead-of-Time (AOT) processing is a build-time phase in which Spring analyses your application’s bean definitions, generates optimized Java source code, and produces GraalVM hint files — all before the application ever runs. On the JVM this reduces startup time by replacing runtime reflection with pre-generated initialization code. For GraalVM native images, AOT processing is a prerequisite: without it, the compiler cannot statically understand your Spring context.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/spring-projects/spring-boot/llms.txt
Use this file to discover all available pages before exploring further.
AOT vs. JIT: what changes at build time
In a standard JVM application, Spring parses@Configuration classes, discovers @Bean methods, and builds the application context at startup using reflection and dynamic proxies. The JIT compiler then optimizes hot code paths over time.
AOT processing shifts the heavy lifting earlier:
| Phase | JIT (standard JVM) | AOT |
|---|---|---|
| Bean definition discovery | Runtime | Build time |
@Configuration parsing | Runtime (reflection) | Build time (source generation) |
| Proxy class generation | Runtime (cglib) | Build time (bytecode) |
| GraalVM hint files | Not required | Generated at build time |
| Startup speed | Baseline | Faster (no reflection overhead) |
AOT cache and Spring’s AOT processing can be combined to further improve startup time on the JVM.
What Spring AOT generates
When the AOT processing phase runs, Spring produces three categories of output:Java source code
Bean definitions are rewritten as direct, reflection-free Java code. Generated sources land in
target/spring-aot/main/sources (Maven) or build/generated/aotSources (Gradle).Bytecode
Dynamic proxy classes generated by cglib are pre-compiled to
.class files. Find them in target/spring-aot/main/classes or build/generated/aotClasses.GraalVM hint files
JSON hint files describing reflection, resources, serialization, proxies, and JNI are written to
META-INF/native-image/{groupId}/{artifactId}/. They are also available in target/spring-aot/main/resources or build/generated/aotResources.Running AOT processing during a build
- Maven
- Gradle
Activate the This triggers the
native profile to include AOT generated code in your JAR:spring-boot:process-aot goal automatically as part of the build lifecycle.Running a JAR with AOT initialization on the JVM
Once you have built a JAR that includes AOT generated code, you can instruct the JVM to use the pre-generated initialization path instead of the standard reflection-based startup:Registering custom runtime hints
Spring AOT generates hints automatically for the vast majority of Spring-managed code. When you use reflection, resources, serialization, or dynamic proxies outside of what Spring can detect statically — for example, in a third-party library or custom infrastructure code — you register additional hints usingRuntimeHintsRegistrar.
Implementing RuntimeHintsRegistrar
Create a class implementing RuntimeHintsRegistrar and make the appropriate calls on the provided RuntimeHints instance:
Activating the registrar with @ImportRuntimeHints
Apply @ImportRuntimeHints on any @Configuration class — including your @SpringBootApplication class — to activate the registrar:
Using @RegisterReflectionForBinding
For classes that need reflection binding — most commonly when serializing or deserializing JSON — annotate a bean with @RegisterReflectionForBinding:
Testing custom hints
UseRuntimeHintsPredicates to write unit tests that verify your RuntimeHints instance includes the entries you registered. With AssertJ:
AOT cache for faster JVM startup
The AOT cache is a JVM feature (available in Java 24+) that records the output of the JVM’s own AOT compiler during a training run and replays it on subsequent starts. Combined with Spring’s AOT processing, it can reduce startup time substantially without requiring a full native image compilation.If you are using Java older than 24, use CDS (Class Data Sharing) instead of the AOT cache. CDS is the predecessor and works similarly.
Extract the application JAR
The AOT cache must be used with the extracted form of the JAR, not the uber JAR:
Run the training pass
- AOT cache (Java 24+)
- CDS (Java < 24)
app.aot, which can be reused as long as the application and Java version remain unchanged.