Core Java

GraalVM Native Image vs Project Leyden: Two Answers to the Same Cold-Start Problem

Leyden’s AOT approach is fundamentally different from GraalVM’s closed-world assumption. Here is what architects actually need to know to choose the right path — and why the answer is probably not either/or.

If you have ever watched a Java pod spin up in Kubernetes — that long, expensive pause before it is actually ready to serve traffic — you have met the cold-start problem firsthand. For years, the only real answer the Java ecosystem offered was GraalVM Native Image: compile everything ahead of time, ship a binary with no JVM, start in under 100 ms. It worked brilliantly for the right workloads. However, for a large portion of enterprise Java, it also introduced a list of compatibility headaches that teams quietly dreaded.

Now there is a second answer. Project Leyden, an OpenJDK initiative that began shipping real features in JDK 24, takes a fundamentally different approach to the same problem. And because the two solutions look superficially similar — both involve doing work before runtime — architects are understandably confused about which path to take, whether these two approaches conflict, and whether one will make the other obsolete.

This article cuts through that confusion. We will look at what each approach actually does at a technical level, where the real trade-offs sit, and how to match the right tool to your specific deployment context.

1. Why cold start is an architecture problem, not just a performance metric

Startup time matters differently depending on where you sit. For a long-running monolith that restarts once a month, a four-second startup is a footnote. However, for a modern deployment landscape, it frequently determines whether Java is even a viable choice:

Deployment contextCold-start impactTarget startup
Serverless / FaaSEvery cold invocation is billed and user-facing; p99 latency directly suffers<100 ms
Kubernetes pod scale-outPods marked ready before JIT warms up; requests hit unoptimized paths for first 10–30 s<500 ms
CLI toolingUsers perceive anything over ~200 ms as “slow to start”<200 ms
Long-running microservicesStartup latency matters less; peak throughput and memory footprint dominate1–5 s acceptable
Batch / scheduled jobsStartup overhead is amortized over run duration; rarely the bottleneck5+ s often fine

The important insight here is that the target startup time varies by roughly two orders of magnitude across these contexts. Consequently, a solution that is perfect for serverless is overkill — or even counterproductive — for a long-running service. Both GraalVM and Leyden understand this; they just optimise for different points on that spectrum.

2. GraalVM Native Image: the closed-world bargain

GraalVM Native Image has been in production use since around 2019 and is now a mature, well-understood technology. The idea is elegant: at build time, the native-image tool performs a deep static analysis — called points-to analysis — starting from your application’s main entry point. It traces every reachable class, method, and resource, and compiles the whole lot into a self-contained native binary. At runtime, there is no JVM to initialise, no bytecode to compile, and no class loading delay. The binary starts instantly.

“Native Image is an optimization that reduces the memory footprint and startup time of an application. This requires a closed-world assumption, where all code is known at image build time — no new code is loaded at run time.”

— GraalVM Native Image Compatibility Guide

The performance results are dramatic. A Spring Boot microservice that takes three to four seconds to start on the JVM routinely boots in under 100 milliseconds as a native image, often with 75% lower RSS memory at runtime. For serverless and rapid scale-out scenarios, those numbers are genuinely transformative.

2.1 The cost of the closed-world assumption

However, “all code is known at build time” is a strong constraint, and it creates a very real class of compatibility problems. Because GraalVM cannot know about anything discovered dynamically at runtime — reflection targets, resources, serialization classes, dynamic proxies — you must either eliminate those patterns or hand-write metadata configuration files that tell the tool what it cannot discover on its own.

Reflection, serialization, dynamic proxies, and runtime class loading all require explicit configuration or they simply disappear from the native binary. Furthermore, the application classpath is fixed at build time — no lazy class loading, no OSGi, no runtime plugin systems. Spring’s own documentation notes that the closed-world assumption means beans cannot change at runtime and certain conditional configurations are unsupported.

In practice, teams adopting GraalVM Native Image typically budget meaningful engineering time for what practitioners call the “reflection audit” — systematically identifying every dynamic usage in both their own code and their dependencies, and producing the corresponding configuration. For greenfield microservices with a carefully chosen dependency set, this is manageable. For large, mature enterprise applications with deep framework dependencies built up over years, it can be genuinely painful.

Startup time comparison — Spring PetClinic–scale application (real benchmark data from OpenJDK / GraalVM)

Source: JEP 483 benchmark data (Spring PetClinic 3.2.0, ~21,000 classes). GraalVM figure from production case studies. Premain branch data from OpenJDK Leyden repository. All times approximate.

3. Project Leyden: the open-world alternative

Project Leyden starts from a different philosophical premise. Rather than requiring you to give up Java’s dynamic capabilities, it asks: what if we could observe what a real application actually does during a representative run, cache that work, and replay it on every subsequent start? In other words, Leyden is built on speculative optimisation — the same foundation that has driven the JVM’s peak performance for decades.

Practically, this means a training run. You run your application once in a mode that records what it does — which classes it loads, which methods it calls most frequently, what objects it constructs during startup. That profile is stored in an AOT cache file. From then on, every production start loads from the cache and avoids repeating work it has already done. Crucially, if a class is not in the cache, the JVM falls back to loading it normally. There is no hard failure, no constraint violation, no compatibility cliff.

The key architectural difference: Leyden makes no closed-world assumption. The AOT cache is a performance hint, not a constraint. Your application remains fully dynamic — reflection, proxies, custom classloaders, and runtime code generation all still work. You simply avoid re-doing the work that was already observed in training.

3.1 The JEP-by-JEP delivery model

Unlike GraalVM, which shipped as a complete, alternative toolchain, Leyden is delivering incrementally — one JEP per JDK release, each addressing a specific category of startup work. This is deliberate: it lets the Java ecosystem adopt each improvement without any migration cost, and it keeps each feature individually reviewable and reversible.

Leyden premain branch — normalised startup time by optimisation layer (lower is better; 1000 = baseline JVM, real data from OpenJDK Leyden repository)

Source: openjdk/leyden premain branch README. Geomean of 10 runs each. A value of 255 means the app starts in 25.5% of baseline time — approximately a 4× improvement.

4. The core philosophical difference

It is worth making the philosophical gap between these two approaches explicit, because this is where the architectural confusion most often originates.

GraalVM Native Image says: “Tell us everything your application could ever do, and we will compile it all into the most optimal binary possible.” The compiler needs a complete, closed view of the world at build time. In exchange, you get the absolute minimum startup time and memory footprint. The trade-off is a hard constraint on dynamism — the tool needs to know about reflection, serialisation, and dynamic proxies ahead of time, or those features simply do not exist in the output binary.

Project Leyden says: “Show us what your application actually does in a representative run, and we will pre-compute as much of that work as possible.” The JVM makes speculative optimisations based on observed behaviour, exactly as the JIT compiler has always done — just shifted earlier in time. In exchange, you keep full Java compatibility. The trade-off is that startup improvements are incremental rather than transformational, and the cache must be regenerated if the application changes significantly.

DimensionGraalVM Native ImageProject Leyden
World modelClosed-world: all code known at build timeOpen-world: full Java dynamism preserved
RuntimeNo JVM; self-contained native binaryStandard HotSpot JVM + AOT cache file
JIT compilerNone at runtime — AOT onlyFull JIT retained; AOT cache accelerates warmup
Reflection supportManual config requiredFull, no changes
Dynamic proxiesMust be registeredSupported natively
Runtime class loadingNot supportedFully supported
Code changes requiredOften significantNone (train + deploy)
Peak throughputCan lag JVM for adaptive workloadsFull JIT peak performance
Startup improvement~40–50× vs baseline JVM~2–4× today; more with premain branch
Memory (RSS)~75% lower than JVMModest improvement; JVM overhead remains
Container image sizeVery small (no JVM needed)Larger (JVM + cache file)
Tooling maturityProduction-ready, rich ecosystemJDK 24–26 features shipping; premain experimental
GraalVM / Oracle dependencyYesNo — standard OpenJDK
Spring Boot supportYes (AOT processing required)Yes (3.3+ out of the box)

5. Choosing the right path for your workload

Rather than treating this as a binary choice, it helps to think of the two approaches as serving different segments of the deployment spectrum. The decision is not primarily about technology preference — it is about workload profile, team capacity, and how much compatibility risk you can absorb.

Lean toward GraalVM Native Image when…

  • Startup under 200 ms is a hard requirement (serverless, CLI tools, rapid auto-scaling)
  • Memory footprint per instance is a primary constraint (dense container packing)
  • Your application is a focused microservice with a well-controlled dependency set
  • You can invest engineering time in the reflection audit and compatibility work
  • You are building new services, not migrating existing ones
  • Peak throughput is less important than startup latency and memory

Lean toward Project Leyden when…

  • You need meaningful startup improvement with zero code changes or compatibility risk
  • Your app is reflection-heavy (Spring, Hibernate, Quarkus CDI) or uses dynamic proxies heavily
  • You are migrating large, mature enterprise applications
  • Peak JIT throughput matters and you cannot accept any regression
  • Your team uses OpenJDK and wants to avoid a vendor dependency on GraalVM
  • You need to support ZGC (fully unlocked as of JDK 26 via JEP 516)

Not a binary choice: Quarkus already supports both paths side by side — plain JVM, Leyden-optimised JVM, and native image are three modes that coexist. As the Quarkus team puts it, “rather than replacing one another, these modes form a spectrum of trade-offs.” The same thinking applies to any modern Java framework.

6. What Leyden is not — and a word on timelines

It is important to be accurate about where Leyden stands today, because the project is sometimes described with more confidence than the current state warrants. As of April 2026, four JEPs have shipped (JDK 24–26), delivering roughly a 40–60% startup improvement for well-configured applications. That is significant, but it is not the same league as GraalVM’s 40–50× improvement for serverless scenarios.

The most exciting Leyden features — ahead-of-time code compilation (pre-compiled native methods) and ahead-of-time dynamic proxy generation — are currently only in the experimental premain branch of the OpenJDK repository, not yet in any released JDK. These are the features that push the premain benchmark down to roughly 25% of baseline startup time. They are real and they work, but they are not production-ready today.

The premain branch benchmark showing startup at 25% of baseline is promising, but it reflects experimental code. Production teams should plan around what is actually shipped: JEP 483 + 514 + 515 (JDK 24–25) for a reliable ~40–50% startup improvement today, with more to come incrementally. Spring Boot 3.3+ supports Leyden’s AOT cache out of the box, and Quarkus has active integration work underway.

7. What we have learned

Throughout this article, we have seen that GraalVM Native Image and Project Leyden are, at their core, two different answers to the same question — not the same answer with different branding. GraalVM solves the cold-start problem by eliminating the JVM entirely and requiring a closed-world view of your application at build time. It delivers transformational startup improvements (sub-100 ms) and dramatic memory savings, at the cost of compatibility constraints and engineering effort. For serverless, CLI tooling, and tightly scoped microservices, those trade-offs are often well worth it.

Project Leyden, by contrast, builds on Java’s open-world model and the JVM’s existing speculative optimisation machinery. It ships incrementally — one JEP per release — and today delivers a solid 40–60% startup reduction with zero code changes and full backward compatibility. It preserves the JIT compiler, reflection, dynamic proxies, and every other dynamic Java capability. For large enterprise applications, migration projects, and teams that cannot afford compatibility risk, it offers a path to meaningfully better startup without any of GraalVM’s constraints.

Furthermore, as Quarkus, Spring, and other frameworks demonstrate, the two approaches are not mutually exclusive. The right architecture increasingly offers both deployment modes, letting teams choose based on workload profile rather than technical ideology. Architects who understand both paths clearly — and resist the temptation to frame this as a competition — will be best positioned as Leyden’s premain features graduate to mainline JDK releases over the next one to two years.

Eleftheria Drosopoulou

Eleftheria is an Experienced Business Analyst with a robust background in the computer software industry. Proficient in Computer Software Training, Digital Marketing, HTML Scripting, and Microsoft Office, they bring a wealth of technical skills to the table. Additionally, she has a love for writing articles on various tech subjects, showcasing a talent for translating complex concepts into accessible content.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Back to top button