Spring Boot 4.1’s Default Virtual Threads Boost Throughput—But Require HikariCP Tuning

Spring Boot 4.1 makes virtual threads the default, dramatically increasing I/O concurrency, yet the unchanged HikariCP maximumPoolSize can exhaust connections; the article explains this incompatibility, shows how to adjust pool settings, enable lazy connections, and outlines a step‑by‑step migration path from 3.x to 4.1.

Java Tech Enthusiast
Java Tech Enthusiast
Java Tech Enthusiast
Spring Boot 4.1’s Default Virtual Threads Boost Throughput—But Require HikariCP Tuning

Why 4.1 is an important upgrade window

Spring Boot 4.0 introduced the most disruptive jump—requiring Java 17+, Jakarta EE 11, Spring Framework 7 and moving Jackson from com.fasterxml.jackson to tools.jackson. Upgrading from 3.x to 4.0 is costly. Spring Boot 4.1 is an incremental enhancement on the 4.0 base, adding many defaults and keeping breaking changes to a minimum, so the migration cost from 4.0 to 4.1 is low.

Virtual threads default: benefits and pitfalls

What are platform threads and virtual threads?

Platform (OS) threads have a 1:1 mapping to kernel threads and consume a large stack (≈512 KB‑1 MB). A typical 8 GB machine can host only a few thousand such threads. Virtual threads, introduced by Project Loom in Java 21, are lightweight JVM‑level threads that are not bound to OS threads. When a virtual thread blocks on I/O, the JVM unloads it to a carrier thread, allowing the carrier to serve other work. The code using synchronized or Thread.currentThread() works unchanged.

In practice, a machine can sustain tens of thousands of concurrent virtual threads because most of them spend time waiting for I/O rather than using CPU.

Spring Boot 4.1 automatically enables virtual threads for Tomcat when running on Java 21+ by setting spring.threads.virtual.enabled=true, requiring no code changes.

Pitfall: connection‑pool exhaustion

HikariCP’s design assumes “fewer connections are better”. Its default maximumPoolSize is 10, and the documentation recommends staying below 20‑30 connections. With traditional Tomcat threads (max 200), this matches the request‑to‑DB concurrency. Virtual threads break this assumption: Tomcat can now accept tens of thousands of requests, and if 5 000 of them hit the database simultaneously, only 10 connections are available, causing the rest to wait and eventually throw SQLTimeoutException.

Fixes

Increase the HikariCP pool size and tune timeouts. Example configuration:

spring:
  datasource:
    hikari:
      # increase connections for virtual‑thread workloads
      maximum-pool-size: 50
      connection-timeout: 3000
      max-lifetime: 1800000

Enable lazy connection acquisition via the new LazyConnectionDataSourceProxy (auto‑configured in 4.1). Add the property spring.datasource.connection-fetch=lazy so a physical connection is only fetched when a SQL statement is executed.

spring:
  datasource:
    connection-fetch: lazy

Combining a higher pool size (e.g., 50) with lazy connections lets you serve many more concurrent requests while using far fewer database connections than a traditional setup.

Other incompatibilities from 3.x to 4.x

Testing annotations: @MockBean must be replaced with @MockitoBean; @SpringBootTest no longer auto‑injects MockMvc or TestRestTemplate —you must add @AutoConfigureMockMvc explicitly.

Jackson migration: change the groupId from com.fasterxml.jackson.core to tools.jackson.core and rename @JsonComponent to @JacksonComponent.

MongoDB configuration: the generic spring.data.mongodb.* namespace is replaced by spring.mongodb.* for connection settings.

Health probes: endpoints /actuator/health/liveness and /actuator/health/readiness are enabled by default; disable them only if your infrastructure restricts actuator access.

Server error properties: move from server.error.* to spring.web.error.*. The spring-boot-properties-migrator tool can detect and suggest these changes.

AOT compilation and GraalVM native images

Spring Boot 4.x continues investing in Ahead‑Of‑Time (AOT) compilation, which pre‑generates bean registration and condition‑evaluation code. When compiled to a native image with GraalVM (native‑image v25+), start‑up time drops from seconds to milliseconds and memory usage can shrink by 50‑80%.

Suitable scenarios: serverless/FaaS functions, edge‑node services with strict memory limits, and CLI tools that need fast start‑up. Unsuitable scenarios: long‑running services that benefit from JIT warm‑up, services that change frequently (re‑compiling native images is costly), and legacy code with heavy reflection.

For most medium‑size Spring Boot services, the immediate benefit comes from virtual threads rather than native images.

Migration path – safest upgrade strategy

Step 1 – Upgrade to 3.5.x (the last 3.x release). This version deprecates many 4.0 breaking changes, allowing the compiler to surface incompatibilities such as @MockBean@MockitoBean. Ensure the build produces zero deprecation warnings.

Step 2 – Upgrade to 4.0.x (current stable 4.0.6). Tasks include migrating Jackson groupId, adjusting configuration namespaces (use the properties‑migrator tool), fixing test annotations, and removing Undertow if present. Perform full integration testing in a non‑production environment.

Step 3 – Upgrade to 4.1.x (RC1, GA soon). Verify and possibly increase maximum-pool-size, enable lazy connection fetching ( spring.datasource.connection-fetch=lazy), and confirm virtual threads are active (check logs).

Rollback strategy – if issues arise, revert the version in pom.xml without touching application code, run full integration tests to capture baseline response times and connection‑pool metrics, and monitor hikaricp.connections.pending and timeout counts after deployment.

Conclusion

Spring Boot 4.1 is worth upgrading, especially for I/O‑bound services that can leverage virtual threads. The key is to adjust the HikariCP pool size or enable lazy connections to avoid the “virtual‑thread‑plus‑tiny‑pool” bottleneck. Follow the staged migration (3.5 → 4.0 → 4.1) and keep a solid rollback plan.

Spring Boot 4.x version baseline comparison
Spring Boot 4.x version baseline comparison
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

migrationspring-bootVirtual ThreadsHikariCPJava 21LazyConnection
Java Tech Enthusiast
Written by

Java Tech Enthusiast

Sharing computer programming language knowledge, focusing on Java fundamentals, data structures, related tools, Spring Cloud, IntelliJ IDEA... Book giveaways, red‑packet rewards and other perks await!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.