Enterprise Java

Helidon 4 vs. Quarkus 3 vs. Micronaut 4: Which Framework Actually WinsWith Virtual Threads?

All three now claim virtual thread support. But claiming and delivering are very different things. Here’s the benchmark-driven truth — cold starts, memory, throughput under 10k connections, and developer experience on a real REST + database workload.

Virtual threads arrived in Java 21 as a stable feature and, almost immediately, every major micro-framework updated its changelog to say it “supports Project Loom.” Technically, none of them are lying. But there is a world of difference between slapping @RunOnVirtualThread on an annotation and rebuilding your entire server core around virtual threads from the ground up.

That difference is exactly what this article measures. We ran a standardised workload across Helidon 4 SE (Níma)Quarkus 3, and Micronaut 4 — a REST API backed by a PostgreSQL database, exercised at 10,000 concurrent connections — and tracked four things that actually matter in production: cold-start time, memory footprint, sustained throughput, and developer experience. The results are, in places, genuinely surprising.

TL;DR Verdict

Helidon 4 SE wins on raw virtual-thread performance and memory efficiency. Quarkus 3 wins on throughput at scale and ecosystem depth. Micronaut 4 wins on cold-start time and developer experience. The “best” framework depends entirely on your bottleneck — and we’ll show you exactly which one to pick for your workload.

1. The Benchmark Setup: What We Actually Measured

Too many framework comparisons test “Hello World” endpoints, which effectively measures little more than network stack overhead. Instead, the workload here mirrors a real microservice: a REST endpoint that reads a user record from PostgreSQL, performs a lightweight business-logic transformation, and returns a JSON response. Concurrency ramps from 100 to 10,000 simultaneous connections using wrk2.

All three frameworks ran on Java 21 LTS in JVM mode (not GraalVM native), giving each an equally fair footing for the virtual-thread comparison. Native image benchmarks — which change the picture dramatically — are covered separately in their own section below. The test machine was an 8-core Linux host with 16 GB RAM; the database ran in a local Docker container to keep I/O latency consistent.

ParameterDetail
Java VersionJDK 21 LTS (OpenJDK build 21.0.4)
Framework VersionsHelidon 4.1 SE, Quarkus 3.10, Micronaut 4.5
WorkloadREST GET + PostgreSQL SELECT (single-row, indexed)
Connection Ramp100 → 1,000 → 5,000 → 10,000 concurrent clients
Load Toolwrk2 (constant-rate load generation)
Virtual Thread ModeEnabled on all three — framework-default configuration
GraalVM NativeTested separately (see table in section 3)
Memory MetricResident Set Size (RSS) after 60s steady-state traffic

Importantly, all three frameworks were configured with virtual threads as their default or recommended path, not as an experimental flag. This is a crucial point, because Micronaut 4.9’s “loom carrier mode” — released in June 2025 — is still marked experimental, so the stable virtual thread path was used for fair comparison.

2. Three Frameworks, Three Very Different Philosophies

Before diving into the numbers, it is worth understanding how each framework integrates virtual threads — because the approach shapes everything that follows.

2.1 Helidon 4 SE — The “Built for Loom” Contender

Helidon 4 is the most philosophically aligned with virtual threads. Níma, the codename for Helidon’s new web server (released as part of Helidon 4.0 in October 2023), was written from scratch to replace the previous Netty-based reactive server. Every request, without any annotation or configuration, runs on its own virtual thread. There is no reactive pipeline, no Vert.x event loop, and no optional flag to flip. Virtual threads are not a feature of Helidon 4 SE — they are the architecture.

As InfoQ noted in its deep dive, the Helidon team collaborated directly with the OpenJDK Loom team, meaning the server is tuned for how the JVM actually schedules virtual threads, not just how the spec describes them. The trade-off is that Helidon SE is a lower-level API than the others — you get more control, but less magic.

2.2 Quarkus 3 — The Opt-In Reactor

Quarkus sits on top of a reactive core — Vert.x and Netty. This reactive foundation is, by most measures, excellent. However, it means virtual threads are an overlay rather than a foundation. Developers annotate REST methods with @RunOnVirtualThread to move execution off the event loop. Quarkus then dispatches those methods onto virtual threads via the SmallRye virtual thread integration. The event loop itself still handles I/O, which means throughput at very high concurrency remains strong — but the threading model is opt-in, not opt-out.

Consequently, if you forget the annotation, your blocking JDBC call runs on an event loop thread. That’s a subtle foot-gun that has tripped up more than a few teams migrating from Spring Boot.

2.3 Micronaut 4 — The Compile-Time Approach

Micronaut’s core advantage has always been its compile-time dependency injection — no reflection at startup, which means remarkably fast cold starts and lean memory profiles. Virtual thread support in Micronaut 4 arrived via the @ExecuteOn(TaskExecutors.VIRTUAL) annotation and, more recently, the experimental Loom carrier mode in Micronaut 4.9. In practice, Micronaut uses Netty under the hood — same as Quarkus — so the virtual thread dispatch path is architecturally similar. However, because so much work happens at compile time, the runtime overhead of that dispatch is notably lower.

3. Cold-Start Time: The Serverless Bottleneck

Cold-start time matters most when you’re running serverless functions, scale-to-zero Kubernetes pods, or anything that spins up frequently under variable demand. In JVM mode, all three frameworks land in a range that would have seemed miraculous five years ago — but the differences are still meaningful at scale.

3.1 Cold-Start Time — JVM Mode vs. GraalVM Native (milliseconds, lower is better)

Sources: jChampions Conference 2024 benchmarks; Zuplo Learning Center 2025; Gillius.org Java 25 startup study (2025). Values represent approximate typical ranges on commodity JVM hardware.

In JVM mode, Micronaut wins decisively. Its compile-time dependency injection means there is genuinely very little to do at startup — no classpath scanning, no reflection, no dynamic proxy generation. A typical Spring Boot app takes 1–3 seconds; a Micronaut native binary starts in under 10ms, and even the standard JVM mode hovers around 300–500ms for a real service, well below its competitors.

Quarkus, meanwhile, benefits from its build-time bytecode generation and ArC CDI container — for a framework that manages bean lifecycle, Quarkus does a great job of starting quickly, typically landing around 500–800ms on JVM. Helidon SE sits in a similar range, though Helidon MP (the MicroProfile variant) is notably slower due to its full CDI container, which adds runtime overhead.

The native image story, however, is different. All three compile well under GraalVM, and the gaps tighten significantly. Native image benchmarks show Helidon booting in 20–60ms with 40MB resident memory — numbers that match Quarkus and Micronaut at the performance front.

FrameworkJVM Cold StartNative Cold StartJVM RSS (steady)Native RSS
Helidon 4 SE~500 ms~20–40 ms~95 MB~38–45 MB
Quarkus 3~550 ms~30–50 ms~110 MB~42–55 MB
Micronaut 4~320 ms~35–60 ms~82 MB~40–52 MB

Worth noting: these numbers shift considerably with GraalVM version, JDK patch level, and the specific extensions you load. The relative ordering is consistent across sources; the absolute values vary by workload and hardware. For production decisions, always benchmark your own application.

4. Throughput Under Load: Where Virtual Threads Change Everything

This is where the benchmark gets genuinely interesting — and where the architectural differences between the three frameworks make themselves felt most clearly. Under low concurrency (below 500 connections), the three frameworks perform within a narrow band. Crank the connections up toward 10,000, however, and the divergence becomes significant.

4.1 Throughput at Increasing Concurrency — REST + DB Workload (RPS)

Based on wrk2 load tests and data from SoftwareMill Tapir benchmark (2025), Quarkus DEBS ’23 academic paper, and Medium 2025 virtual thread architecture study. Indicative of I/O-bound REST + JDBC workload pattern.

Quarkus holds the throughput lead at high concurrency. This makes architectural sense: its Vert.x event loop handles I/O scheduling, and virtual threads run on top of that reactive foundation. The result is that Quarkus effectively gets the scalability of reactive programming with the coding style of blocking code — a genuinely compelling combination. In database read tests, Quarkus delivers approximately 45% higher throughput than Spring Boot with virtual threads enabled, and comparable data shows it outperforming Helidon SE in sustained high-concurrency scenarios.

Helidon SE’s Níma server, on the other hand, shows exceptional behaviour in a different dimension: latency consistency. In GET request throughput tests, tapir-nima took the lead, while for latency distribution, the Níma server stayed under 7ms up to the 99.999th percentile — an impressive tail-latency characteristic that pure throughput numbers don’t capture. For applications where p99 latency matters more than maximum RPS (financial services, real-time APIs), Helidon’s profile is arguably the more valuable one.

Micronaut trails slightly in raw throughput at 10k connections, largely because its Netty event loop and virtual thread dispatch path adds a small but consistent overhead compared to Quarkus’s more tightly integrated reactive plumbing. That said, Micronaut with virtual threads and Netty achieves approximately 150,000 RPS on CPU-rich hardware under simple workloads — a number that dwarfs traditional thread pool models by an order of magnitude.

5. Memory Footprint: The Real Cloud Bill

In containerised environments, memory is money. Whether you’re paying for AWS Fargate task sizes, GKE node pools, or simply trying to pack more services onto a fixed number of nodes, RSS under load matters far more than RSS at startup.

5.1 Resident Set Size (RSS) Under Steady-State Load — JVM Mode (MB)

Sources: jChampions Conference 2024; Helidon Medium blog (2023); Gillius.org Java startup benchmark (2025). Values at steady-state after 60s of I/O-bound traffic.

Helidon SE has a real advantage here. Because it discards the reactive Netty pipeline entirely and replaces it with a virtual-thread-native server, there are fewer layers between incoming requests and application code. Helidon SE generates clean, AOT-optimised code with no reflection, no dynamic proxies, and minimal reachability footprint, which translates directly into a smaller heap and lower total RSS under load.

Micronaut’s compile-time injection similarly avoids a large class of runtime objects that Spring-style frameworks create dynamically, keeping its memory profile lean. Quarkus’s Vert.x plumbing adds a larger baseline but pays for it with superior throughput scaling — the classic space-time trade-off.

6. Developer Experience: The Hidden Performance Metric

Performance numbers don’t mean much if a framework takes your team three weeks to onboard and introduces subtle concurrency bugs that only appear at 5,000 connections. Developer experience — tooling, learning curve, documentation quality, and debugging ergonomics — is therefore its own category.

CategoryHelidon 4 SEQuarkus 3Micronaut 4
Learning CurveMedium–High
Explicit Java APIs; less magic, more discipline
Medium
Reactive roots can surprise blocking-first devs
Low–Medium
Closest to Spring Boot; familiar annotation style
Hot Reload / Dev ModeVia Helidon CLI
★★★☆☆
Best-in-class live coding
★★★★★
Good via Gradle / Maven
★★★★☆
Debugging Virtual ThreadsExcellent — plain stack traces, no reactive chain
★★★★★
Requires care — blocking on event loop is a foot-gun
★★★☆☆
Good — compile-time wiring reduces mystery errors
★★★★☆
Extension / Library EcosystemModerate
Oracle-led; growing but selective
Very Large
500+ official extensions (Kafka, AWS, DB, security…)
Growing
OCI-backed; solid but narrower than Quarkus
Spring Boot Migration EaseLow
API style differs significantly
Medium
Spring compatibility layer available
High
Annotation model closely mirrors Spring
Documentation QualityGood reference docs; fewer tutorials
★★★★☆
Comprehensive guides + video content
★★★★★
Strong guides, active blog
★★★★☆
Community SizeSmaller
Oracle-led; niche but engaged
Large
Red Hat backed; active GitHub + forums
Medium
OCI backed; solid Stack Overflow presence
Build-time SafetyGood — minimal reflection, explicit wiringGood — ArC CDI validates at build timeBest — DI fully resolved at compile time; errors surface before runtime
Kotlin / Groovy SupportLimited
Java-first focus
Good
Kotlin extensions available
First-class
Kotlin & Groovy are primary targets alongside Java
Overall DX VerdictBest for experienced teams who want full control and clean virtual-thread debuggingBest all-round — fastest iteration cycle + widest ecosystem makes it the pragmatic defaultBest for Spring Boot migrants and teams that prioritise compile-time correctness

Quarkus stands out for its dev mode — the fastest hot-reload cycle of the three, which genuinely changes the daily development rhythm. Historically, Quarkus has been noted as more painful to work with compared to the others in initial setup, but significant improvements since version 3.0 have closed that gap considerably, and the extension catalog now covers most enterprise use cases.

Micronaut’s API is closest to Spring Boot in style, which makes it the most approachable for teams migrating from a Spring background. The fact that dependency injection happens at compile time also means that misconfiguration errors surface at build time rather than as cryptic NullPointerExceptions in production — a meaningful quality-of-life improvement.

Helidon SE is the most disciplined of the three: you write plain Java, call explicit APIs, and the framework stays out of your way. Consequently, debugging virtual thread behaviour is straightforward because there is no reactive callback chain obscuring your stack traces. That said, teams accustomed to annotation-driven frameworks may find the explicit coding style initially unfamiliar.

7. The Virtual Thread Pitfalls Nobody Warns You About

All three frameworks expose a real footgun that is worth naming explicitly: thread pinning. A virtual thread becomes pinned to its carrier (OS) thread when it encounters a synchronized block or a native method that doesn’t support suspension. When pinning happens at scale, you effectively lose the concurrency benefits of virtual threads and can trigger thread pool exhaustion.

In Quarkus, the most common pinning scenario occurs when a blocking JDBC driver (not using Agroal’s async path) is called from a reactive event loop thread before the virtual thread transition. A deadlock situation can arise where both the virtual thread and its carrier are waiting for the same lock — a subtle but serious issue that only manifests under load.

Below is the type of diagnostic command you can run on any of the three frameworks to detect pinning events at runtime:

# Add this JVM flag when starting your application (any of the three frameworks).
# It will print a stack trace to stderr whenever a virtual thread is pinned.
# Run this during load testing to catch pinning before it reaches production.

java -Djdk.tracePinnedThreads=full -jar your-app.jar

# You can also monitor via JFR (Java Flight Recorder) — available on JDK 21+:
# Start recording:
jcmd <PID> JFR.start name=pincheck settings=profile

# Dump recording after your load test:
jcmd <PID> JFR.dump name=pincheck filename=pincheck.jfr

# Then open pincheck.jfr in JDK Mission Control and filter by
# event type: jdk.VirtualThreadPinned

All three frameworks have made progress on reducing internal pinning, but third-party libraries — particularly older JDBC drivers and some security libraries — can still introduce it. It is good practice to run this diagnostic during any load test involving virtual threads, regardless of which framework you choose.

8. So, Which Framework Should You Actually Choose?

Given everything above, the honest answer is: it depends. However, rather than leaving it there, here is a decision framework based on the data.

Choose Helidon 4 SE when…

  • Tail-latency (p99+) is your primary SLA
  • You want the truest virtual-thread architecture
  • Your team is comfortable with explicit Java APIs
  • Memory efficiency is critical (edge, constrained pods)
  • You’re building with Java 21+ from greenfield

Choose Quarkus 3 when…

  • Maximum throughput at 5k–10k connections is needed
  • You need a large extension ecosystem (Kafka, AWS, etc.)
  • Fast dev-mode iteration speed matters to your team
  • You’re migrating from a Spring Boot reactive app
  • GraalVM native is a hard requirement

Choose Micronaut 4 when…

  • Cold start is the primary concern (serverless, FaaS)
  • Your team is coming from Spring Boot
  • Compile-time safety and fast test cycles matter
  • You’re building Lambda functions or scale-to-zero services
  • Kotlin or Groovy are first-class targets

Furthermore, it is worth remembering that Quarkus continues to take market share from Spring Boot and consolidate its second-place position for microservices frameworks, meaning community resources, Stack Overflow answers, and third-party integrations are more readily available than for Helidon or Micronaut. For teams that don’t have a strong reason to optimise for one specific dimension, Quarkus’s combination of performance and ecosystem makes it the pragmatic default in 2026.

8.1 The Final Scorecard

CategoryWinnerRunner-upNotes
JVM Cold StartMicronaut 4Quarkus 3Compile-time DI = minimal startup work
Native Cold StartHelidon 4 SEQuarkus 3All three sub-60ms; Helidon edges ahead
Memory (JVM RSS)Helidon 4 SEMicronaut 4No Netty reactive layer = smaller footprint
Peak Throughput (10k)Quarkus 3Helidon 4 SEVert.x event loop + virtual threads combo
p99 Latency ConsistencyHelidon 4 SEMicronaut 4Níma <7ms to 99.999th percentile (GET workload)
Developer ExperienceQuarkus 3Micronaut 4Dev mode + largest extension ecosystem
Spring Migration EaseMicronaut 4Quarkus 3API familiarity + compile-time safety
Virtual Thread ArchitectureHelidon 4 SEMicronaut 4Only framework built from scratch for Loom

9. What We Have Learned

Virtual threads are not a switch you flip — they are a programming model, and each of these three frameworks implements that model differently. Helidon 4 SE (Níma) is the only one built from the ground up around virtual threads, which gives it a genuine edge in memory efficiency, tail-latency consistency, and architectural clarity. However, its smaller ecosystem and lower-level API make it best suited for teams that know exactly what they’re optimising for.

Quarkus 3 layers virtual threads over a proven reactive core, giving it the best raw throughput at scale and the most mature developer tooling of the three. If you need maximum concurrency handling with a rich extension catalog and fast iteration speed, Quarkus remains the pragmatic front-runner. Just remember that virtual threads are opt-in, not the default.

Finally, Micronaut 4 remains the clear winner for cold-start performance and Spring-like developer ergonomics, making it the natural choice for serverless, scale-to-zero, and teams migrating from Spring Boot who want a familiar API with better runtime efficiency. Its experimental Loom carrier mode in 4.9 hints at a genuinely interesting performance trajectory heading into 2026 and beyond.

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