Member-only story
Spring Boot 4 Virtual Threads
If you are coming from Spring Boot 3, you already know the drill. Tomcat gives you a pool of 200 platform threads. Every request grabs one, and if that thread sits waiting on a database call or a slow downstream API, it is doing nothing but holding a chunk of memory. Run out of threads and requests queue up, even though your CPU is bored.
Spring Boot 4 makes the fix a one-line change. But the one line is the easy part. The thing that actually breaks in production is ThreadLocal. This post is about both.
Turning virtual threads on
Spring Boot 4.0 requires Java 21 as a minimum, and Java 24 or later is what you want in production (more on why below). Once you are on it, this is the whole switch:
spring.threads.virtual.enabled=trueThat one property tells the embedded Tomcat to hand each request a fresh virtual thread instead of borrowing one from the fixed pool. @Async tasks and Spring’s TaskExecutor pick it up too. Your controllers, services, and repositories do not change at all:
@RestController
@RequiredArgsConstructor
@Slf4j
public class OrderController {
private final OrderService orderService;
@GetMapping("/orders/{id}")
public OrderResponse getOrder(@PathVariable Long id) {
log.info("Fetching order {}", id)…








