Spring Boot 4.0 is the biggest release since the 3.0 jakarta migration. Virtual threads are now the default. GraalVM AOT is first-class. The modular starter redesign cleans up years of dependency bloat. Spring Framework 7 brings built-in API versioning. If you're still on 3.x, your migration window is closing.
What Version Are We Even On?
As of April 2026, Spring Boot 4.0.6 is the current stable release, and 4.1.0-RC1 just dropped on the Spring blog. Spring Boot 3.5 β the last 3.x line β loses open-source support on June 30, 2026, so the upgrade train is no longer optional.
The version ladder that matters right now:
| Release | Status | Support Until |
|---|---|---|
| Spring Boot 4.0.6 | β Current stable | Dec 31, 2026 |
| Spring Boot 4.1.0-RC1 | π¬ Release candidate | β |
| Spring Boot 3.5.x | β οΈ Maintenance only | Jun 30, 2026 |
| Spring Boot 3.4.x | β EOL | Dec 31, 2025 |
The Big 5 Things That Actually Matter
1. π§΅ Virtual Threads Are Now the Default
This is the headliner. In Spring Boot 3.2, virtual threads (Project Loom) were opt-in behind a flag. In 4.0, they're the recommended threading model on Java 21+ β the auto-configuration detects your JVM version and adjusts thread pools accordingly. No code changes required.
// Your existing blocking JDBC code? It just⦠works better now.
@GetMapping("/orders/{id}")
public Order getOrder(@PathVariable long id) {
// Blocking call β but cheap on a virtual thread π
return orderRepository.findById(id).orElseThrow();
}
Tomcat and Jetty handlers use virtual threads by default on Java 21+. @Async tasks and scheduled operations follow the same model. The "virtual threads vs reactive" debate has largely been settled: for most standard I/O-heavy Spring MVC apps, you get reactive-scale throughput with imperative code simplicity.
One important caveat: virtual threads excel at I/O-bound workloads. CPU-intensive apps won't benefit as much, and you'll want to audit thread-local storage patterns since virtual threads can create millions of instances.
2. ποΈ Modular Starter Redesign
The starters got a significant overhaul. Previously, pulling in spring-boot-starter-web dragged along a lot of optional integrations you might never use. The new design separates optional integrations (Micrometer, OpenTelemetry, specific persistence technologies) into dedicated modules.
The practical wins:
- Faster builds β AOT processing has less unnecessary metadata to churn through
- Cleaner dependency trees β only what you declare, not what Spring assumed you wanted
- Better GraalVM native image support β fewer reflection hints needed for unused paths
If you use starter POMs, your pom.xml or build.gradle doesn't change. The modularization happens underneath. For teams doing native compilation, the build time improvements are immediately noticeable.
3. π’ Built-in API Versioning (Spring Framework 7)
Spring Framework 7 ships under the hood, and one of its headline features is first-class API versioning support β no more custom interceptors or messy URL path gymnastics.
@RestController
@RequestMapping("/api/greet")
public class GreetingController {
@GetMapping(version = "1")
public Map<String, String> greetV1() {
return Map.of("message", "Hello!");
}
@GetMapping(version = "2")
public Map<String, String> greetV2() {
return Map.of(
"message", "Hello!",
"timestamp", LocalDateTime.now().toString()
);
}
}
Spring handles the routing. You declare the version; the framework dispatches it. For anyone building long-lived public APIs with multiple client generations, this alone is worth the upgrade conversation.
4. π Unified Observability (OpenTelemetry + Micrometer)
The observability story in 4.0 is significantly cleaner. Configuration that previously required manual bean registration is now auto-configured:
- Single property namespace for configuring OTLP exporters
- Built-in trace-to-log correlation out of the box
- Simplified Grafana and Prometheus setup through new starter dependencies
-
spring-boot-starter-actuatornow includes observability defaults
# One block to rule your telemetry
management:
otlp:
tracing:
endpoint: http://otel-collector:4318/v1/traces
tracing:
sampling:
probability: 1.0
If you've been manually wiring ObservationRegistry beans or fighting with Micrometer context propagation, the new defaults will feel like a breath of fresh air.
5. π GraalVM AOT Goes Mainstream
Native image support has been in Spring since 3.0, but it always felt like a second-class citizen β reflection configuration was finicky, build times were brutal, and dynamic features broke in unexpected ways. Boot 4.0 changes that posture:
"Spring Boot 4.0 provides first-class framework support for both AOT compilation and virtual threads, eliminating the integration friction that plagued earlier adoption attempts."
The AOT engine now handles most common reflection patterns automatically. Third-party libraries increasingly ship GraalVM metadata out of the box. If you tried native images on 3.x and hit walls, it's worth retesting on 4.0.
Real-world benchmark from the Project Leyden team: Spring PetClinic starts 41% faster with AOT caching enabled in JDK 26. That's not GraalVM native territory, but it's approaching it β without rewriting code or giving up the JIT.
What Got Removed
Know before you upgrade:
| Removed | Replacement |
|---|---|
WebSecurityConfigurerAdapter |
SecurityFilterChain beans |
| Undertow embedded server | Tomcat or Jetty (Undertow β Servlet 6.1 compatible) |
spring.config.use-legacy-processing |
N/A β removed entirely |
RestTemplate auto-configuration |
RestClient (imperative) or @HttpExchange (declarative) |
| Spring Retry as separate dependency | Built-in resilience via @Retry and @ConcurrencyLimit
|
The RestTemplate one trips people up. It's not gone β but its auto-configuration is now opt-in. If you have RestTemplate beans autowired across your codebase, plan to migrate to RestClient:
// Old way (still works, but no longer auto-configured)
@Autowired
private RestTemplate restTemplate;
// New way β RestClient (Spring Framework 6.1+)
private final RestClient restClient = RestClient.create();
public String fetchData(String url) {
return restClient.get()
.uri(url)
.retrieve()
.body(String.class);
}
Migration Path
From Spring Boot 3.4/3.5 β 4.0: Smooth if you've been cleaning up deprecation warnings. No namespace migration (that was the 2.x β 3.x jump). Main watchpoints: Spring Security 7 new defaults, removed deprecated APIs, and JSpecify null-safety annotations.
From Spring Boot 2.x β 4.0: Don't do this in one shot. Migrate 2.x β 3.5 first, stabilize, then go to 4.0. You'll hit the javax.* to jakarta.* namespace change regardless, and stacking that on top of the 4.0 changes is pain you don't need.
<!-- Update your parent POM -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.0.6</version>
</parent>
Minimum Java version: 17. Recommended: 21 or 25 to actually benefit from virtual threads and the newer JVM features.
What's on the Horizon: Spring Boot 4.1
The 4.1.0-RC1 is already out with some interesting additions:
-
AMQP 1.0 spec support β auto-configuration of
AmqpConnectionFactoryandAmqpClient -
Spring Batch + MongoDB β new
spring-boot-batch-data-mongomodule - Spring AI deeper integration β the ecosystem is converging on AI-native patterns fast
Spring AI deserves its own post, honestly β but the short version is that Java developers in 2026 have roughly the same toolkit for agentic AI development as Python developers, without needing to stand up separate services.
The Bottom Line
Spring Boot 4.0 isn't just an incremental patch release β it's a reset. Virtual threads make high-throughput I/O trivial. The modular redesign clears out years of accumulated dependency weight. Native images have finally crossed from "experimental" to "production-viable." And Spring Framework 7's API versioning fixes one of the oldest annoyances in REST API design.
If you're on 3.5.x, your support window closes June 30. If you're on 3.4.x or earlier, you're already in EOL territory. The upgrade path is genuinely smoother than 2.x β 3.x was β no namespace migration, just deprecation cleanup.
There's no good reason to wait.
Thanks for reading! Drop a π¬ if you've already migrated to 4.0 β curious what pain points you hit and what surprised you positively.

Top comments (0)