Go to homepage
Join us

Why the Future of Java Performance Starts with Java 21

Blogpost Thumbnail - Java 21.jpg

In real projects, there is a constant challenge that never goes away: optimizing the use of available resources. At the time, the focus is on performance; at others, it shifts to reducing infrastructure costs. Increasingly, it is also about sustainability – using only what’s needed, and nothing more. That’s the first of the "3 Rs": reduce, reuse, recycle.

Upgrading Java versions is rarely just about staying current. For us, the move to Java 21 was a strategic decision with clear technical goals in mind. We wanted to improve responsiveness, cut down CPU and memory consumption, and enable the system to scale more efficiently. At the same time, the upgrade offered an opportunity to strengthen security and ensure better compatibility with modern libraries and frameworks.

In this article, we will walk through why Java 21 meets our needs, the actual benefits we saw, and how other teams might face similar decisions.


Java Has Changed – And so Have the Requirements

Modern Java evolves fast. Since Java 9, the platform has adopted a 6-month release cycle with Long-Term Support (LTS) versions every two years. Java 21 is the current LTS, supported until 2029.

But even more importantly, modern application requirements have shifted:

  • APIs must handle high concurrency efficiently.

  • Frameworks like Spring Boot 3.3 require Java 17+.

  • Cloud deployments require fast startup and a low memory footprint.

  • Security policies demand regular updates to runtime environments.

Sticking to older Java versions like 11 or even 17 might work for now, but the ecosystem is clearly moving forward – and fast.


Why Java 21? Practical Benefits We've Seen Firsthand

Java 21 isn’t just another version bump; it brings a series of language and runtime features that make a real difference in day-to-day development. Some of them are game-changers for performance and scalability, while others simply make code cleaner and easier to maintain. Here are a few highlights we’ve explored and tested in our migration.

1. Virtual Threads (JEP 444 – GA)

Traditional thread-based concurrency in Java (one thread per request) is expensive and hard to scale. Virtual threads, introduced in Java 21 as a stable feature, change the game.

They allow lightweight concurrency, enabling the handling of thousands of tasks with far fewer hardware resources. In Spring Boot 3.2+, enabling virtual threads is as simple as: properties spring.threads.virtual.enabled=true

What we noticed in practice:

  • Better CPU usage and lower memory footprint.

  • Improved response times under high load.

  • Fewer headaches with thread pool tuning.

2. Structured Concurrency (JEP 453 - Preview)

Still in preview, structured concurrency brings a clearer and safer way to manage multiple tasks that run together. While it is not ready for full production usage yet, it shows where Java is headed: safer, more maintainable concurrency patterns.

3. Pattern Matching and Record Patterns

Java’s pattern matching improvements simplify code, especially when working with immutable DTOs or value objects. They help keep service logic clean, declarative, and maintainable.

4. Sequenced Collections (JEP 431)

New APIs that give direct access to the first and last elements in ordered collections – these are great for streaming pipelines, queues, or ordered batch processing.


JVM Performance Improvements – Especially For Kafka

Our applications rely heavily on Kafka and Apache Camel, so JVM-level improvements have a noticeable impact. With Java 21, we’ve seen meaningful gains across the board: the latest G1 and ZGC garbage collectors deliver shorter pause times and smoother throughput, while faster warm-up and startup make a difference even before considering native image compilation. The enhanced Java Flight Recorder (JFR) also provides richer profiling and diagnostics capabilities, giving us clearer insight into runtime behavior.

In Kafka-heavy projects, these improvements translate into more stable consumer performance under load, lower memory pressure per instance, and reduced cloud infrastructure requirements — benefits that also contribute to a smaller environmental footprint.


Security, Compatibility, and Library Support

Running an outdated Java version isn’t just a technical inconvenience — it’s a security risk. Staying current with the latest Long-Term Support (LTS) release ensures ongoing protection through critical security patches, along with greater stability and performance.

Upgrading matters for several reasons. Java 8 and 11 are no longer freely supported by Oracle, and many widely used libraries have already dropped compatibility with runtimes older than Java 17. Java 21, on the other hand, offers long-term support until 2029, giving teams a stable foundation for years to come.

It also keeps your environment compatible with modern tooling, including:

  • Spring Boot 3.x (version 3.1+ requires Java 17, with Java 21 recommended for full support and future compatibility — Spring Boot 3.3 now includes Java 21 baseline testing).

  • Frameworks such as Hibernate ORM, Micronaut, Quarkus, Apache Camel, and Apache Kafka, which are now optimized and patched primarily for Java 21.

  • Development utilities like Checkstyle, SpotBugs, Mockito, and Lombok, which increasingly target Java 21 features.

  • GraalVM Native Image, which has ended support for Java 11 and is expected to phase out Java 17 once Java 25 (the next LTS) becomes standard.

By upgrading, organizations align with the modern Java ecosystem, stay secure by default, and reduce both technical debt and operational risk over time.


Java 21 in Kubernetes: Efficient, Scalable, Responsible

For applications deployed in Kubernetes – whether microservices, Camel routes, or monolithic architectures – Java 21 offers clear advantages in resource efficiency, scalability, and environmental sustainability, especially when combined with Native Image capabilities (stay tuned for future posts diving deeper into this topic).

General Advantages of Java 21 in Kubernetes

Upgrading to Java 21 brings tangible benefits for containerized workloads in Kubernetes environments. The most immediate improvement comes in startup performance. Applications boot faster, allowing containers to spin up and scale in response to demand with much less delay. For example, an average Spring Boot application that took around 15 seconds to start on Java 11 now launches in about 11 seconds on Java 21 – roughly a 15% improvement thanks to Just-In-Time (JIT) optimization.

Memory management has also seen a significant upgrade. The enhanced JVM in Java 21 reduces the overall memory footprint of applications running in Kubernetes pods, making it possible to deploy more services on fewer nodes. In some cases, we’ve observed up to 50% less heap usage and a 30% reduction in total memory consumption without even changing the garbage collector. Using the new Generational GC, memory consumption can drop from 3 GB to about 1.5 GB.

These optimizations lead to more efficient resource utilization across clusters. Virtual threads allow the system to handle more concurrent tasks with less overhead, while improvements to the garbage collection algorithm reduce latency and enhance overall application efficiency.

When paired with GraalVM Native Image, Java 21 takes these gains even further.

  • Smaller container sizes: Native Image produces compact binaries — in our tests, a Java 17 image built with JIB was 225 MB, compared to only 33.6 MB for a Java 21 Native Image.

  • Near-instant startup: Containers start almost immediately, with startup times dropping from 415 milliseconds on Java 17 to just 3 milliseconds on Java 21 Native Image.

  • Lower memory footprint: Native Image removes unused parts of the JVM, cutting memory consumption dramatically — from roughly 49 MB to just 2 MB in our comparisons.


Why These Benefits Matter

In Kubernetes, these improvements translate directly into cost efficiency and sustainability. Faster startup and lower memory usage reduce the need for additional infrastructure, lowering both cloud spending and resource overhead. At the same time, running more lightweight, efficient workloads supports a more sustainable approach to software operations by minimizing compute and energy consumption.

In short, Java 21 makes Kubernetes applications more responsive, scalable, and resource-conscious — all critical qualities for modern, cloud-native environments.

Java 21 in Kubernetes allows applications to scale more efficiently, consume fewer resources, and deploy faster, which is critical when operating in resource-constrained environments like Kubernetes clusters.


Native Image and Kubernetes: Efficiency in Cloud and On-Prem Environments

Java 21 is the first fully supported LTS version for Native Image compilation through GraalVM, offering significant advantages in containerized deployments – not only in the cloud, but also in on-premise environments using Kubernetes or similar platforms. With its ability to compile applications into native executables, Native Image removes much of the runtime overhead traditionally associated with the JVM, enabling highly optimized cloud and cluster native workloads.

One of the most immediate benefits is faster scaling at a lower cost. Applications built with Java 21 and Native Image start almost instantly, eliminating the warm-up period that often delays JVM-based services. Because each instance uses less memory and CPU, scaling becomes more efficient and economical. Teams can scale aggressively during load spikes without worrying about resource waste, improving resilience and reliability under unpredictable traffic conditions.

Native Image is also well-suited for Function-as-a-Service (FaaS) and serverless architectures. Its near-instant startup and low memory footprint make Java competitive with traditionally lighter languages in these environments. Combined with Java’s mature tooling and ecosystem, this allows teams to build fast, flexible, and production-ready serverless applications.

Another advantage of Native Image compilation is that it naturally promotes leaner, more secure deployments. During compilation, GraalVM analyzes the entire codebase and its dependencies, encouraging teams to review and refine what actually needs to be included. In practice, most libraries fall into three categories:

  • Native-compatible libraries: modern libraries that work out of the box with Native Image.

  • Partially compatible libraries: those that require small adjustments or metadata configurations (such as reflect-config.json, resource-config.json, or jni-config.json) to handle reflection or dynamic resources. Tools like GraalVM’s Reachability Metadata and tracing agents simplify this process.

  • Incompatible or unnecessary libraries: components that rely heavily on runtime bytecode manipulation or dynamic class loading and must often be replaced or excluded.

This process encourages more modular and deliberate architecture decisions, often resulting in simpler, more maintainable applications with smaller binaries and a reduced attack surface.

Deployed in Kubernetes, Java 21 Native Images combine these advantages into a highly efficient runtime: faster scaling, lower resource consumption, and more sustainable use of shared cluster capacity, whether you’re running in the public cloud, a private data center, or at the edge.


Migration Tips That Actually Help

If you’re planning a migration to Java 21, the following practical steps can help ensure a smooth transition. These recommendations come directly from our own experience upgrading production systems.

  • Analyze dependencies with jdeps Use this tool to identify any internal or unsupported APIs your application may still rely on.

  • Scan for deprecated APIs with jdeprscan Detect outdated or soon-to-be-removed APIs early to prevent compatibility issues later in the process.

  • Build minimal runtimes with jlink Create custom Java runtimes tailored to your application’s needs. This is especially useful for containerized deployments or Native Image builds, helping reduce the overall runtime footprint.

  • Verify framework and library compatibility Confirm that Spring Boot and all key dependencies officially support Java 21 or are actively maintained. (Spring Boot 3.3, for example, includes Java 21 baseline testing.)

  • Automate testing early Run integration and regression tests under Java 21 as soon as possible. Add them to your CI pipeline so potential issues surface quickly during development.

  • Evaluate performance with virtual threads enabled If you’re using Spring Boot, activate virtual threads by setting:

    spring.threads.virtual.enabled=true

    This provides valuable insights into performance improvements and helps reveal any behavioral changes introduced by the new concurrency model.


Java 21 as a Strategic Upgrade

Upgrading Java is more than just a technical exercise; it’s a strategic decision that shapes how your systems perform, scale, and evolve. Java 21 delivers modern language features, stronger performance right out of the box, and the security of long-term support. It aligns seamlessly with today’s cloud-native tools and frameworks, while laying the groundwork for what’s next, from Native Image to Project Loom.

Ultimately, Java 21 enables teams to do more with less, building systems that are not only faster and more efficient but also more sustainable. For projects focused on efficiency, scalability, and long-term growth, upgrading isn’t just a nice-to-have — it’s essential.

Juan Carlos Conca Vidal

Juan Carlos Conca Vidal is a results-oriented professional with extensive experience in software architecture, team leadership, and backend development. His focus are business requirements, considering both technical feasibility and business functionality.