Spring Boot 3 to Spring Boot 4 Guided Migration
Spring Boot 4 is not as disruptive as the Boot 2 to Boot 3 migration, but it is still a major upgrade. The safest path is:
current Boot 3.x -> latest Boot 3.5.x -> Boot 4.x
Spring's Boot 4.0 Migration Guide recommends upgrading to the latest available 3.5.x first, reviewing deprecations, checking dependency compatibility, and then moving to the latest Boot 4 maintenance release.
Migration Goal
By the end of this guide, the application should:
- run on Spring Boot 4.x
- use Spring Framework 7.x compatible dependencies
- compile without removed Boot 3 APIs
- use the new or renamed starters intentionally
- pass unit, slice, and integration tests
- expose the same operational endpoints that production depends on
Phase 0: Decide If The App Is Ready
Do this before touching the version number.
| Check | Why it matters |
|---|---|
| Already on latest Boot 3.5.x | Reduces the number of changes in the Boot 4 jump. |
| No Boot 3 deprecation warnings ignored | Deprecated Boot 3 APIs and properties may be removed in Boot 4. |
| Java 17+ in CI and production | Boot 4 requires Java 17 or later. Java 21 or newer is a better target for long-lived services. |
| Third-party libraries support Spring Framework 7 / Jakarta EE 11 | Your application can fail because of ecosystem dependencies, not only Spring Boot itself. |
| No reliance on Boot 4 removed integrations | Undertow, reactive Pulsar, Spring Session Hazelcast/MongoDB, and Boot Spock support are gone. See Removed in Boot 4. |
| Null-safety tooling reviewed | Boot 4 uses JSpecify annotations; Kotlin and static analysis setups may surface new errors. |
| Test suite covers startup, web, security, persistence, and observability | Major upgrades punish weak integration tests. |
Phase 1: Upgrade To Latest Boot 3.5 First
Upgrade your current application to the latest Spring Boot 3.5 line before moving to 4.x.
For Maven:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.x</version>
</parent>
For Gradle:
plugins {
id 'org.springframework.boot' version '3.5.x'
}
Then:
- Run the full test suite.
- Fix warnings from deprecated Spring Boot APIs, properties, and annotations.
- Check the dependency tree for libraries that pin old Spring, Jakarta, Jackson, Hibernate, Tomcat, Jetty, or testing versions.
- Commit this as a separate migration baseline.
Phase 2: Review The Platform Baseline
| Area | Boot 3.5 | Boot 4 |
|---|---|---|
| Java minimum | Java 17 | Java 17 |
| Recommended Java | Java 21 | Java 21 or newer |
| Spring Framework | 6.2 | 7.x |
| Jakarta EE | Jakarta EE 10 generation | Jakarta EE 11 |
| Servlet API | Servlet 6.0 | Servlet 6.1 |
| Kotlin | Earlier Kotlin 2.x | Kotlin 2.2+ |
| GraalVM native image | GraalVM 22.3+ | GraalVM 25+ |
| Gradle | Gradle 7.6+/8.x | Gradle 8.14+ or Gradle 9 |
Important point: Java 17 is still supported. You do not have to do a Java migration just to start Boot 4, but Java 21 is usually the healthier production target. See Spring Boot 4 system requirements.
Phase 3: Change The Boot Version
For Maven:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.0.x</version>
</parent>
For Gradle:
plugins {
id 'org.springframework.boot' version '4.0.x'
}
Now run:
./mvnw clean test
# or
./gradlew clean test
Expect failures. The first target is not "all green"; the first target is to classify failures into dependency, source-code, property, test, and runtime categories.
Phase 4: Replace Renamed Starters
Spring Boot 4 is more modular. Some older starter names still exist temporarily, but are deprecated. Prefer the new explicit names.
The naming pattern is now more consistent:
spring-boot-<technology>
spring-boot-starter-<technology>
spring-boot-<technology>-test
spring-boot-starter-<technology>-test
| Boot 3 starter | Boot 4 starter |
|---|---|
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-client |
HTTP clients are also more explicit:
| Use case | Starter |
|---|---|
RestClient / RestTemplate | spring-boot-starter-restclient |
Reactive WebClient | spring-boot-starter-webclient |
Common migration mistake: the old application relied on transitive dependencies. After modularization, add the starter for the technology you actually use.
Frequent misses after modularization:
spring-boot-starter-flyway
spring-boot-starter-liquibase
spring-boot-starter-security-test
spring-boot-starter-data-jpa-test
If a slice test or migration tool worked before only because another starter pulled it in transitively, add the matching technology starter explicitly.
Phase 5: Handle Jackson 3
Spring Boot 4 uses Jackson 3 by default. Many imports move from:
com.fasterxml.jackson...
to:
tools.jackson...
Jackson annotations remain under:
com.fasterxml.jackson.annotation
Review:
- custom serializers and deserializers
- custom
ObjectMapperbeans - JSON test helpers
- libraries that still require Jackson 2
- configuration properties under
spring.jackson.*
Boot 4 auto-configures format-specific mapper types:
JsonMapper
XmlMapper
Defining a generic ObjectMapper bean may no longer replace Boot's JSON mapper. Prefer a JsonMapper bean when you need to customize JSON serialization.
Some properties become more specific:
# Boot 3
spring.jackson.read...
spring.jackson.write...
# Boot 4
spring.jackson.json.read...
spring.jackson.json.write...
If a dependency is not ready for Jackson 3, Boot 4 provides a deprecated Jackson 2 compatibility module. Treat it as a temporary bridge, not the final state:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-jackson2</artifactId>
</dependency>
See Introducing Jackson 3 support in Spring and the Jackson section of the Boot 4 migration guide.
Phase 6: Update Tests
Replace Boot Mockito Annotations
Boot-specific annotations are removed:
@MockBean
@SpyBean
Use Spring Framework annotations:
@MockitoBean
@MockitoSpyBean
Example:
@SpringBootTest
class OrderServiceTest {
@MockitoBean
private PaymentService paymentService;
}
Do not blindly search and replace. The new annotations are not valid in every old location, especially inside some test configuration patterns.
Review JSpecify Nullability
Boot 4 and the wider Spring portfolio use JSpecify nullability annotations. Annotations such as org.springframework.lang.Nullable should generally move to org.jspecify.annotations.Nullable. Code that compiled under Boot 3 may expose new nullable or non-nullable compilation errors under Boot 4, especially in Kotlin projects and codebases using static null analysis.
Add Explicit Test Auto-Configuration
@SpringBootTest is less magical in Boot 4. Add the test client you need explicitly.
For MockMvc:
@SpringBootTest
@AutoConfigureMockMvc
class ControllerTest {
}
For HTTP-server style tests:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureRestTestClient
class ApiIntegrationTest {
}
Boot 4 introduces RestTestClient, which can test both MockMvc-backed applications and real running HTTP servers.
Phase 7: Review Web And Server Changes
Boot 4 moves to Servlet 6.1 and newer embedded servers:
- Tomcat 11
- Jetty 12.1
- Servlet 6.1
Undertow support has been removed. If your app uses Undertow, plan that as a separate migration decision rather than a quick dependency swap.
For WAR deployments to an external Tomcat server, use the runtime Tomcat starter:
<artifactId>spring-boot-starter-tomcat-runtime</artifactId>
Removed in Boot 4
Confirm the application does not depend on these before upgrading:
- Undertow as an embedded server
- Reactive Spring Pulsar support
- Embedded Unix launch scripts for fully executable JARs
- Spring Session Hazelcast
- Spring Session MongoDB
- Boot's Spock integration
@MockBeanand@SpyBean- Deprecated Boot 3 APIs, classes, and properties
Review Spring Security 7
Boot 4 ships with Spring Security 7. For many applications, Security breaks before Boot-specific code does. If you can, prepare on Spring Security 6.5 while still on Boot 3.5 using the Preparing for 7.0 guide, then finish with the Migrating to 7.0 steps after the Boot 4 bump.
Also confirm the renamed OAuth2 client starter from Phase 4: spring-boot-starter-security-oauth2-client.
Watch for these Security 7 changes
1. Lambda DSL is required for HttpSecurity
The old chained style with .and() is no longer valid. Every HttpSecurity and ServerHttpSecurity configuration must use the lambda DSL:
http
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()
)
.formLogin(formLogin -> formLogin
.loginPage("/login")
.permitAll()
);
If login or authorization rules behave differently after the upgrade, this is often the first place to look. See Configuration migrations.
2. PathPatternRequestMatcher replaces Ant and MVC matchers
AntPathRequestMatcher and MvcRequestMatcher are no longer supported. Security 7 expects PathPatternRequestMatcher for requestMatchers(...) and related filter URLs.
Watch for:
- custom
setFilterProcessingUrl(...)calls on authentication filters SwitchUserFilterexit/switch URLs- apps deployed behind a non-default servlet path prefix
- JSP taglibs or custom
WebInvocationPrivilegeEvaluatorusage
If /api/** suddenly does not match the path you expect, review Web migrations.
3. Method security needs parameter names at runtime
If you use expressions like @PreAuthorize("@authz.check(#id)"), compile with -parameters so Spring can resolve method parameter names. Spring Framework 7 removed LocalVariableTableParameterNameDiscoverer, so missing parameter metadata now fails at runtime instead of silently mis-resolving. See Authorization changes.
4. OAuth2 resource server JWT validation changed
If you customize NimbusJwtDecoder, typ header validation moves from Nimbus internals to JwtTypeValidator. Custom jwtProcessorCustomizer type checks should be migrated before Boot 4 if you rely on non-default JWT header behavior. See OAuth 2.0 changes.
5. Security serialization moves to Jackson 3
Security's Jackson integration changes from SecurityJackson2Modules / ObjectMapper to SecurityJacksonModules / JsonMapper.Builder. This overlaps with Phase 5, but auth-heavy apps should test login, remember-me, OAuth2 login, and any persisted security context serialization explicitly.
If you use Spring Authorization Server, it now defaults to Jackson 3 as well.
Security-focused tests to run
- form login and logout flows
- CSRF-protected POST endpoints
- OAuth2 login and resource server endpoints
- method-level
@PreAuthorize/@PostAuthorizerules - session or remember-me persistence across restarts
Phase 8: Review Data And Persistence
Boot 4 upgrades major data libraries, including:
- Hibernate ORM 7.1
- Jakarta Persistence 3.2
- Hibernate Validator 9
- HikariCP 7
- Flyway 11
- Liquibase 5
- Testcontainers 2
- Kafka 4.1
- MongoDB driver 5.6
Run targeted tests for:
- repository query methods
- custom JPQL and native SQL
- entity mappings
- validation annotations
- database migrations
- transaction boundaries
- Testcontainers setup
For Spring Batch, spring-boot-starter-batch uses an in-memory job repository by default. If you need database-backed job metadata, use:
<artifactId>spring-boot-starter-batch-jdbc</artifactId>
Also review ecosystem migration notes, not only Boot itself:
Elasticsearch
The old low-level Elasticsearch RestClient auto-configuration is replaced by Rest5Client. Customizers also change:
RestClientBuilderCustomizer // Boot 3
Rest5ClientBuilderCustomizer // Boot 4
MongoDB
Many properties move from spring.data.mongodb.* to spring.mongodb.*:
spring.mongodb.uri=
spring.mongodb.database=
spring.mongodb.username=
spring.mongodb.password=
UUID and BigDecimal representations may also need explicit configuration after the driver upgrade.
Redis
Redis observability is based more directly on Spring's Observation API, producing both metrics and spans. Validate dashboards and tracing after the upgrade if Redis is on the critical path.
Phase 9: Update Configuration Properties
Add the Spring Boot properties migrator temporarily:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-properties-migrator</artifactId>
<scope>runtime</scope>
</dependency>
Start the app and read the migration diagnostics. Fix renamed or removed properties, then remove the migrator.
Examples to check:
# Boot 3
spring.data.mongodb.*
# Boot 4
spring.mongodb.*
# Boot 3
management.tracing.enabled
# Boot 4
management.tracing.export.enabled
Actuator liveness and readiness probes are exposed by default:
/actuator/health/liveness
/actuator/health/readiness
If needed:
management.endpoint.health.probes.enabled=false
Other smaller but potentially surprising changes:
- Logback output defaults more consistently to UTF-8.
- DevTools LiveReload is disabled by default.
- Maven optional dependencies are no longer placed inside executable uber JARs by default.
- JDK-based HTTP clients use virtual threads when
spring.threads.virtual.enabled=true. - Spring Retry is no longer version-managed by Spring Boot; prefer Spring Framework retry support where possible.
Phase 10: Use New Capabilities Intentionally
Do not mix feature adoption with the core migration unless the feature directly simplifies the upgrade.
Consider these after the app is stable:
| Feature | Why it matters | Official reference |
|---|---|---|
| HTTP Service Clients | Spring can generate clients for @HttpExchange interfaces. | HTTP Service Client enhancements |
| Built-in API versioning | MVC and WebFlux gain API versioning auto-configuration. | API versioning in Spring |
| OpenTelemetry starter | Boot 4 can auto-configure the OpenTelemetry SDK and OTLP export. | Boot 4 migration guide |
| JSpecify null safety | Better static analysis, especially for Kotlin and null-sensitive codebases. | Null-safe applications with Boot 4 |
API versioning can be configured with properties such as:
spring.mvc.apiversion...
spring.webflux.apiversion...
Example HTTP Service Client:
@HttpExchange("/users")
public interface UserClient {
@GetExchange("/{id}")
User getUser(@PathVariable Long id);
}
Pull Request Checklist
Use this as the migration PR review checklist.
- Application first upgraded cleanly to latest Boot 3.5.x
- Deprecated Boot 3 APIs and properties removed
- Java, Kotlin, Gradle, and GraalVM baselines reviewed
- New Boot 4 starter names used where applicable, including Flyway, Liquibase, and test starters
- Jackson 3 imports,
JsonMappercustomizations, andspring-boot-jackson2bridge usage reviewed -
@MockBeanand@SpyBeanreplaced intentionally -
@SpringBootTesttests have explicit client auto-configuration where needed - JSpecify/nullability changes reviewed for Kotlin and static analysis tooling
- Spring Security 7 migration notes reviewed, including lambda DSL, path matchers, method security, OAuth2 JWT validation, and Security Jackson 3
- Spring Data 2025.1 release notes reviewed
- Undertow and other removed integrations confirmed absent
- Data-library upgrade risks tested, including Elasticsearch, MongoDB, and Redis if used
- Batch job repository behavior checked
- Actuator, tracing, metrics, and health probes validated
- Properties migrator run and then removed
- Production smoke test completed
Common Failure Map
| Symptom | Likely cause | First fix |
|---|---|---|
| Missing web classes | Starter modularization | Add spring-boot-starter-webmvc, restclient, or webclient explicitly. |
| Flyway or Liquibase no longer runs | Transitive starter removed | Add spring-boot-starter-flyway or spring-boot-starter-liquibase explicitly. |
| Slice test context fails to start | Missing technology test starter | Add the matching spring-boot-starter-*-test dependency. |
| Jackson imports fail | Jackson 3 package move | Update imports to tools.jackson.* where required. |
| Custom JSON config ignored | ObjectMapper bean no longer overrides Boot defaults | Define a JsonMapper bean instead. |
| Mock-based tests fail | @MockBean removed | Move to @MockitoBean and adjust placement. |
| MockMvc not injected | @SpringBootTest no longer provides it automatically | Add @AutoConfigureMockMvc. |
| New Kotlin/null-analysis errors | JSpecify migration | Replace Spring nullability annotations with org.jspecify.annotations.*. |
| Security config fails to compile | Lambda DSL now required | Rewrite HttpSecurity config to lambda style; remove .and() chaining. |
| Authorization rules no longer match | PathPatternRequestMatcher migration | Replace Ant/MVC matchers and review servlet path prefixes. |
@PreAuthorize fails on #param names | Parameter names not available at runtime | Compile with -parameters and retest method security. |
| JWT resource server rejects valid tokens | typ header validation moved | Migrate custom JWT type checks to JwtTypeValidator. |
| Login or OAuth2 flow breaks after Jackson upgrade | Security Jackson 3 migration | Move from SecurityJackson2Modules to SecurityJacksonModules and test auth flows. |
| Security config breaks at runtime | Other Spring Security 7 changes | Review the Security 7 migration guide. |
| Repository or query behavior changed | Spring Data 2025.1 / Hibernate 7 | Review Spring Data 2025.1 and Hibernate 7 migration notes. |
| Batch metadata no longer written to DB | Batch starter default changed | Use spring-boot-starter-batch-jdbc. |
| Elasticsearch client wiring fails | RestClient replaced by Rest5Client | Update customizers to Rest5ClientBuilderCustomizer. |
| MongoDB config ignored | Property prefix changed | Move settings from spring.data.mongodb.* to spring.mongodb.*. |
| Undertow dependency fails | Undertow support removed | Move to Tomcat or Jetty. |
| Health endpoint output changed | Probes exposed by default | Validate or configure liveness/readiness groups. |
Official References
Spring Boot
- Spring Boot 4.0 Migration Guide
- Spring Boot 4.0 Release Notes
- Spring Boot Upgrade Documentation
- Spring Boot 4.0 System Requirements
- Spring Boot 4.0.0 available now
Spring portfolio
- Spring Framework 7.0 GA
- Spring Security migration guide
- Preparing for Spring Security 7.0
- Spring Data 2025.1 Release Notes
- Modularizing Spring Boot
- Introducing Jackson 3 support in Spring
- Null-safe applications with Spring Boot 4
- API versioning in Spring
- HTTP Service Client enhancements
Data and infrastructure libraries
This guide is based on project experience and the official Spring migration notes. Treat it as a guided checklist, then verify critical production decisions against the official docs for the exact Boot 4.x version you adopt.