r/SpringBoot • u/fykup • 2d ago
Discussion I compared Spring Boot with four other Java stacks on a 512 MiB VPS
I've been experimenting with resource-efficient Java applications, exploring how much of Spring Boot's familiar architecture can be preserved with smaller frameworks.
I compared five Java stacks on a 1-vCPU, 512 MiB VM with no swap, running MariaDB alongside the application.
| Stack | HotSpot RSS (MiB) |
|---|---|
| Spring Boot + Spring JDBC | 180.6-187.9 |
| Javalin + CoilBase | 120.9-135.6 |
| Micronaut Data JDBC | 174.0-175.0 |
| Micronaut + CoilBase | 166.5-167.6 |
| Avaje Jex + CoilBase | 116.0-116.4 |
The HotSpot tests used OpenJDK 27 with G1 GC. Each stack had two runs, with 1,500 requests per run and no errors.
CoilBase is a small Jdbi-based foundation I'm developing. The Javalin, Jex, and Micronaut implementations reuse the same services, repositories, and transaction boundaries, with different HTTP frameworks and application wiring.
The interesting part wasn't just the memory savings. It was seeing how much of the familiar Spring-style application architecture could remain unchanged when switching frameworks.
I also tested GraalVM Native Image for all five stacks. Runtime memory dropped further, but native compilation introduced additional build time and complexity.
This is a lightweight synthetic workload, not a throughput benchmark or a general recommendation to replace Spring Boot. Spring's ecosystem and conveniences still have real value.
Full experiment, measurements, and limitations:
https://pvrlabs.xyz/articles/five-java-stacks-512mb-vps.html
Source code and benchmark setup:
https://github.com/PVRLabs/experiments/tree/main/java/coilbase-framework-comparison
CoilBase, which I built and used for this comparison:
https://github.com/PVRLabs/coilbase
I'm curious whether others see value in a lighter Java stack that keeps some of Spring Boot's familiar development patterns, or whether Spring Boot's ecosystem and conveniences outweigh the potential resource savings.
Update: Framework versions used in the benchmark
| Stack | Versions |
|---|---|
| Spring Boot + Spring JDBC | Spring Boot 4.1.1, Spring JDBC 7.0.9 |
| Javalin + CoilBase | Javalin 7.2.4, Jdbi 3.55.0 |
| Avaje Jex + CoilBase | Jex 3.6, Avaje HTTP 3.12.1, Jdbi 3.55.0 |
| Micronaut Data JDBC | Micronaut 5.2.11, Micronaut Data JDBC 5.2.0 (platform BOM 5.2.1) |
| Micronaut + CoilBase | Micronaut 5.2.11, Jdbi 3.55.0 |
All HotSpot runs used OpenJDK 27 with identical JVM settings: -Xms16m -Xmx80m -XX:+UseG1GC (fixed 80 MiB maximum heap).
CoilBase was an early 0.1.0-SNAPSHOT prototype. I'm working on a more formal, publicly reproducible follow-up benchmark using an updated version of CoilBase, with Quarkus also joining the comparison.
3
u/FriendshipCalm3162 1d ago
Did all five runs use the same -Xmx? If nothing sets it, HotSpot caps the heap with MaxRAMPercentage, which defaults to 25%, so about 128 MiB on that box, and part of each RSS number is just how far G1 grew the heap before it settled. Rerunning all five with one fixed -Xmx would tell you how much of the 65-70 MiB gap between Spring Boot and Jex comes from the framework itself.
1
u/fykup 1d ago
All five HotSpot stacks used the same JVM settings:
-Xms16m -Xmx80m -XX:+UseG1GC, so the maximum heap was fixed at 80 MiB rather than using the default MaxRAMPercentage.You're right that RSS also reflects differences in committed heap and native memory, so this doesn't isolate framework overhead. The goal was to measure complete application stacks under identical resource constraints and workloads.
2
u/FriendshipCalm3162 23h ago
That clears it up, thanks. I'd missed that -Xmx80m was fixed across all five, so with the same ceiling everywhere the RSS spread is mostly committed heap, metaspace and thread stacks rather than retained heap.
For the formal benchmark, -XX:NativeMemoryTracking=summary read with jcmd VM.native_memory gives the per-category split, and GC.run followed by GC.heap_info gives the live set after a collection. NMT costs 5 to 10% throughput though, so it's a side run rather than the headline numbers.
2
u/American_Streamer Junior Dev 1d ago
Imo the most revealing finding is that Spring Boot itself operated successfully alongside MariaDB on just 512 MiB RAM. So the real question isn't whether Spring Boot is unnecessarily heavy. It's whether the additional capabilities it provides justify their resource costs for a particular application.
For a small, straightforward backend on a cheap VPS, the lighter frameworks look really attractive. But for a substantial business application with complex integrations and a team maintaining it for years, I wouldn't abandon Spring Boot over approximately 70 MiB of RAM.
2
u/fykup 1d ago
I agree. Spring Boot running successfully alongside MariaDB on a 512 MiB VPS is a useful finding in itself. For many applications, its additional capabilities are well worth the resource cost.
The tradeoff becomes more interesting when running multiple services or JVM instances. An extra 70 MiB per instance can add up quickly at scale.
I'm not suggesting replacing Spring Boot everywhere, just exploring where lighter alternatives make sense without giving up Java.
1
u/sansp00 22h ago
For enterprise, this means learning and supporting two frameworks with their respective upgrade paths and support contracts. This cost way more than the 70MiB of RAM, even at scale.
2
u/fykup 22h ago
I agree. For large enterprise applications, the cost of introducing and maintaining another framework can easily outweigh the memory savings.
That's why I'm not particularly focused on enterprise adoption. I'm more interested in individual developers, small teams, and applications where resource efficiency and simplicity matter.
CoilBase is also designed to keep persistence and business logic independent of the HTTP framework, which makes switching frameworks easier if requirements change. But I certainly don't expect large, established Spring Boot applications to migrate just to save 70 MiB of RAM.
3
u/anoppe 1d ago
It would have been nice to see how quarkus compared to the rest