What's new, and how to migrate from Spring Boot 3 to 4
The first major release since 2022 brings one module per technology, Jackson 3, JSpecify null safety and built-in API versioning. Most of the upgrade is renaming. Watch out for the few changes that compile fine but behave differently.
Last free 3.5 releaseSpring Boot 3.5.16 is the last free 3.x release. Later 3.x fixes need commercial support.15
Spring Boot 4.2 RC14Final release not published yet.
What's new
One module per technology
The old auto-configuration jar had grown to 2 MiB, and every class and property in it showed up in your IDE. Now each technology gets its own module, starter and test starter, all following the naming scheme below.14
Spring Boot 1.0, 2014
182 KiB
Spring Boot 3.5, 2025
2 MiB
Module
spring-boot-flyway
Starter
spring-boot-starter-flyway
Test starter
spring-boot-starter-webmvc-test
Package
org.springframework.boot.flyway
Jackson 3 by default
New group ID and package (tools.jackson), immutable mappers, unchecked exceptions, and support for java.time without an extra module.1
// Spring Boot 3.ximport com.fasterxml.jackson.databind.ObjectMapper;// Spring Boot 4import tools.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.annotation.JsonProperty; // unchanged
The auto-configured mapper is now a JsonMapper. A custom ObjectMapper bean no longer replaces it, so declare your own JsonMapper bean instead.
Every Jackson module on the classpath is registered automatically. Turn this off with spring.jackson.find-and-add-modules=false.
Not ready to switch? The spring-boot-jackson2 module lets you stay on Jackson 2 while you migrate. It is deprecated and will be removed in a later release.
API versioning
Map one path to several versions. The version can come from a header, a query parameter, the path or the media type.7
@GetMapping(path = "/orders", version = "1.0")
OrderV1 orderV1(...)
@GetMapping(path = "/orders", version = "1.1+")
OrderV2 orderV2(...)
"1.1+" matches 1.1 and every later version. WebFlux uses spring.webflux.apiversion.*. On the client side, RestClient, WebClient, WebTestClient and MockMvc can send a version with each request.
HTTP service clients
Declare an interface with @HttpExchange methods and Spring generates the implementation. Put clients into groups and set the base URL and timeouts per group in properties.8
Import from org.springframework.resilience.annotation, not Spring Retry's package of the same name. For programmatic retries, use RetryTemplate with a RetryPolicy. Spring Kafka and Spring AMQP now use this retry support instead of Spring Retry.
Null safety
All Spring projects now declare nullness with JSpecify. Spring's own @Nullable and @NonNullApi are deprecated.15
Switch to org.jspecify.annotations.Nullable. Kotlin reads these annotations, so Kotlin code that calls Spring APIs may need extra null handling to compile.
OpenTelemetry starter
spring-boot-starter-opentelemetry sets up the OpenTelemetry SDK and exports metrics and traces over OTLP.217
Micrometer has its own modules now, so you can record metrics without pulling in the full Actuator.
Testing
RestTestClient is a blocking counterpart to WebTestClient. It works against MockMvc or a running server.2
Spring Boot now manages JUnit 6. Cached test contexts that sit idle are paused and restarted when a test needs them again.5
Spring Security 7
Adds multi-factor authentication. Spring Authorization Server is now part of Spring Security.9
The and() chaining method is removed. Configure each part with a lambda, such as http.csrf(csrf -> ...). authorizeRequests and AntPathRequestMatcher give way to authorizeHttpRequests and PathPatternRequestMatcher. The OAuth2 password grant is removed.
Spring Data repository code generated at build time (AOT) for faster startup10
spring-boot-starter-kotlin-serialization for JSON with kotlinx.serialization2
Clients built on the JDK HttpClient use virtual threads when spring.threads.virtual.enabled=true2
Multiple TaskDecorator beans are applied together, in @Order order2
A logging.console.enabled switch to turn console logging off2
Migrating from 3 to 4
Get to the latest 3.5.x
Fix every deprecation warning. Anything deprecated in 3.x is gone in 4.0.
Check your toolchain and dependencies
Java 17 is still the minimum, and Java 25 is supported. Kotlin needs 2.2+, Gradle 8.14+. Spring Cloud needs 2025.1 (Oakwood). Confirm every other library supports Spring Boot 4.
Switch to Spring Boot 4
Add spring-boot-properties-migrator as a runtime dependency. At startup it logs renamed properties and temporarily maps them to the new names.
Compile with classic starters
spring-boot-starter-classic and -test-classic pull in every module. Fix moved imports and the Jackson 3 changes until it compiles.
Move to focused starters
Swap the classic starters for one starter and one test starter per technology.
Test for changed behavior
Run the full test suite, work through the dark box below, then remove the properties migrator.
OpenRewrite automates much of steps 1 to 5 with the recipe org.openrewrite.java.spring.boot4.UpgradeSpringBoot_4_0.16
Find and replace
The renames most projects hit. For properties, the migrator reports any others.1
Old names in Spring Boot 3 and their replacements in Spring Boot 4
Starters
spring-boot-starter-web
spring-boot-starter-webmvc
spring-boot-starter-web-services
spring-boot-starter-webservices
spring-boot-starter-aop
spring-boot-starter-aspectj
spring-boot-starter-oauth2-client
spring-boot-starter-security-oauth2-clientSame pattern for resource-server and authorization-server