Spring Boot starts slower than its developers would like, mainly because the JVM has to find, load, verify and link thousands of classes — and Spring then has to build the application context — every single time. Project Leyden is the OpenJDK effort to shift some of that work to a training run ahead of time, and its first results are already in the JDK you probably run: the AOT cache.
No code changes, no native-image build, no reflection configuration. You run your app once to record what it loads, and every later start reuses that work.
What landed in which JDK
JDK 24 introduced ahead-of-time class loading and linking (JEP 483): classes are loaded and linked during a training run and stored in a cache. JDK 25 — the current LTS — made it much simpler to use, creating the cache in a single training run with one flag (JEP 514), and added method profiles to the cache (JEP 515) so the JIT compiler warms up faster. JEP 483's own measurements showed the Spring PetClinic sample starting roughly 40% faster.
Using it with Spring Boot
The AOT cache needs a plain classpath of jars, not Spring Boot's nested "fat" jar. So step one is to extract the jar, which Spring Boot supports out of the box. Then do a training run and point future runs at the cache:
-Dspring.context.exit=onRefresh makes Spring Boot start the context and exit as soon as it has refreshed — a convenient, repeatable training run. A training run that also exercises real requests gives the JIT richer profiles, at the cost of a more involved build.
Baking it into a container image
The cache is only valid with the same JDK build and the same classpath it was created with. The simplest way to guarantee that is to create it inside the image you ship:
Both stages use the same base image, so the cache matches the runtime. If the cache doesn't match — a different JDK build, a changed jar — the JVM ignores it and starts normally, so a stale cache costs you speed, not correctness.
On Kubernetes, a faster start also means shorter startup probes and faster scale-out — see the Spring Boot on Kubernetes checklist. On AWS Lambda, the Java 25 runtime already uses AOT caches; the Lambda cold-start guide covers the other options.
Frequently asked questions
What is the Java AOT cache?
A cache created during a training run that stores classes already loaded and linked — and, from JDK 25, method profiles — so later JVM starts skip that work. It comes from OpenJDK's Project Leyden and needs no code changes.
How do I create an AOT cache for a Spring Boot app?
Extract the jar with java -Djarmode=tools -jar app.jar extract, run it once with -XX:AOTCacheOutput=app.aot (optionally with -Dspring.context.exit=onRefresh), then start the application with -XX:AOTCache=app.aot.
Which Java version do I need for the AOT cache?
Ahead-of-time class loading and linking arrived in JDK 24. JDK 25 added the single-step -XX:AOTCacheOutput workflow and method profiling, so Java 25 LTS is the practical minimum.
-XX:AOTCacheOutput.spring.context.exit=onRefresh makes training easy.