// OSSeva Blog
MigrationSpring Boot 3.5 to 4 Upgrade Guide: Breaking Changes and How to Find Each
The short answer
Upgrade to the latest 3.5 release first, then move to Spring Boot 4.1 rather than 4.0. Java 17 is still the minimum, so most teams do not need a new JDK. The work is in five places: dependencies, because Boot 4 ships smaller modules and some technologies now need their own starter; JSON, because Jackson 3 changes group IDs, package names and several Boot class names; tests, because @MockBean is gone and @SpringBootTest no longer sets up MockMvc on its own; servers, because Undertow is no longer supported and external containers must implement Servlet 6.1; and everything deprecated in 3.x, which has been removed.
Spring Boot 3.5 left open source support on 30 June 2026. Spring Boot 4.0 leaves it on 31 December 2026, and 4.1 is supported until 31 July 2027, so 4.1 is the target that buys time.
Supported upgrade paths
| From | To | Guidance |
|---|---|---|
| Latest 3.5.x (3.5.16) | 4.0.x or 4.1.x | The path the migration guide describes. Start from the newest 3.5 release. |
| 3.0 to 3.4 | 4.x | Move to 3.5 first. The 4.0 release notes strongly recommend it. |
| 2.7 or earlier | 4.x | Do the javax to jakarta move and the 3.x upgrade first. See the Spring Boot 2 to 3 migration guide. |
| 4.0.x | 4.1.x | A minor upgrade on the same Spring Framework 7.0 line. Classes, methods and properties deprecated in 4.0 are removed. |
Support dates that set the deadline
| Line | Open source support ends | Commercial support ends | Latest release |
|---|---|---|---|
| 3.5 | 30 June 2026 | 30 June 2032 | 3.5.16 |
| 4.0 | 31 December 2026 | 31 December 2027 | 4.0.8 |
| 4.1 | 31 July 2027 | 31 July 2028 | 4.1.1 |
| 4.2 | 31 December 2027 | 31 December 2028 | Milestones; spring.io lists the first release for November 2026 |
Commercial support means Broadcom's paid Spring releases. The dates are on the Spring Boot 3.5 end of life and Spring Boot 4.0 end of life pages.
Pre-upgrade checklist
- Every application builds on Spring Boot 3.5.16 with deprecation warnings visible, and the warnings are cleared.
- JDK 17 or later in the build and at runtime. Kotlin projects on 2.2 or later. Native images built with GraalVM 25 or later.
- Gradle 8.14 or later, or Gradle 9.
- For war deployments, the target container implements Servlet 6.1, such as Tomcat 11.0 or Jetty 12.1.
- Every dependency Boot does not manage, Spring Cloud being the usual one, has a release that supports Boot 4.
- A list of the Jackson features, custom serializers and
ObjectMapperbeans each service relies on. - The 3.5 artifact for each service kept in your repository manager, so the previous build can be redeployed.
Breaking change 1: the platform baseline moved
Spring Boot 4 is built on Spring Framework 7, Jakarta EE 11 and Servlet 6.1, and manages Tomcat 11.0 and Jetty 12.1. Java 17 remains the minimum; Spring Framework 7 recommends JDK 25. If you manage Spring dependencies yourself, you must move to Spring Framework 7.x.
Spring Framework 7 no longer supports annotations from the javax.annotation and javax.inject packages, such as @javax.annotation.PostConstruct, @javax.annotation.Resource and @javax.inject.Inject. If the old jars are still on the classpath the code compiles, but Spring no longer acts on those annotations, so the failure shows up at runtime. Find them before the upgrade:
grep -rnE "import javax\.(annotation|inject)\." src/
Replace them with the jakarta.annotation and jakarta.inject equivalents. Our javax to jakarta migration post covers the wider namespace change.
Breaking change 2: Undertow is no longer supported
Undertow does not yet implement Servlet 6.1, so Spring Boot 4 removed the Undertow starter and the option to run Undertow as the embedded server. Spring Framework 7 also removed its Undertow-specific WebSocket and WebFlux classes. Check each build:
mvn dependency:tree | grep -i undertow
./gradlew dependencies --configuration runtimeClasspath | grep -i undertow
Applications that used Undertow need to move to Tomcat, Jetty or Reactor Netty, and any Undertow-specific tuning in server.undertow.* properties has to be redone for the new server.
Breaking change 3: modules and starters were split up
Spring Boot 4 ships smaller modules named spring-boot-<technology>, each with its own root package org.springframework.boot.<technology> and a matching starter. Two things break:
- Technologies that used to work with only the third-party jar. Flyway and Liquibase are the common cases: the application now needs
spring-boot-starter-flywayorspring-boot-starter-liquibase, or the auto-configuration is missing and migrations do not run at startup. - Imports of auto-configuration classes. Packages moved with the modules. For example,
@EntityScanis now inorg.springframework.boot.persistence.autoconfigure.
Several starters were renamed. The old names still work in 4.0 but are deprecated:
| Old starter | New starter |
|---|---|
| spring-boot-starter-web | spring-boot-starter-webmvc |
| spring-boot-starter-web-services | spring-boot-starter-webservices |
| spring-boot-starter-oauth2-client | spring-boot-starter-security-oauth2-client |
| spring-boot-starter-oauth2-resource-server | spring-boot-starter-security-oauth2-resource-server |
| spring-boot-starter-aop | spring-boot-starter-aspectj (check whether you use AspectJ at all) |
Test infrastructure follows the same pattern, with a spring-boot-starter-<technology>-test companion for each starter. For example, @WithMockUser now needs spring-boot-starter-security-test to work properly.
To get an application compiling quickly, the migration guide offers spring-boot-starter-classic and spring-boot-starter-test-classic, which put all modules back on the classpath. Use them as an intermediate step: fix imports with the classic starters in place, then remove them and add the specific starters the build reports as missing.
Breaking change 4: Jackson 3 is the default
Spring Boot 4 prefers Jackson 3, which moves from the com.fasterxml.jackson group and packages to tools.jackson. The exception is jackson-annotations, which keeps the com.fasterxml.jackson.annotation package, so annotations on your DTOs do not change. Find the code that does:
grep -rnE "com\.fasterxml\.jackson\.(databind|core|datatype|dataformat)" src/
grep -rnE "@JsonComponent|@JsonMixin|Jackson2ObjectMapperBuilderCustomizer|ObjectMapper objectMapper\(" src/
What changes with it:
@JsonComponentis now@JacksonComponentand@JsonMixinis now@JacksonMixin.Jackson2ObjectMapperBuilderCustomizerbecomesJsonMapperBuilderCustomizer.- Boot auto-configures a
JsonMapperand anXmlMapper. Declaring anObjectMapperbean no longer replaces them; declare aJsonMapperbean instead. spring.jackson.read.*andspring.jackson.write.*moved tospring.jackson.json.read.*andspring.jackson.json.write.*.- Jackson now registers every module it finds on the classpath, not only well-known ones. Set
spring.jackson.find-and-add-modules=falseto keep the old behaviour.
Jackson 3 also changed defaults. Setting spring.jackson.use-jackson2-defaults=true brings the auto-configured mapper as close as possible to Spring Boot 3.x behaviour, which matters when other services, caches or message queues read the JSON you write. For libraries that still need Jackson 2, Boot keeps dependency management for it, and a deprecated spring-boot-jackson2 module exists as a stop-gap. Jersey is one such case: Boot 4.0 supports Jersey 4.0, which does not yet support Jackson 3.
Breaking change 5: tests lose implicit setup
@MockBeanand@SpyBeanwere removed. Use@MockitoBeanand@MockitoSpyBean.@SpringBootTestno longer provides MockMvc. Add@AutoConfigureMockMvc.@SpringBootTestno longer providesTestRestTemplateorWebClientbeans. Add@AutoConfigureTestRestTemplateplus thespring-boot-resttestclientandspring-boot-restclientdependencies, or move to the newRestTestClientwith@AutoConfigureRestTestClient.MockitoTestExecutionListener, deprecated in 3.4, is gone. Fields annotated with Mockito's@Mockor@CaptorneedMockitoExtension.
grep -rlE "@MockBean|@SpyBean" src/test | wc -l
grep -rlE "MockMvc" src/test | xargs grep -L "AutoConfigureMockMvc"
Breaking change 6: renamed properties and changed behaviour
Add the properties migrator for the first run on Boot 4. It prints every renamed or removed property it finds at startup and maps them temporarily:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-properties-migrator</artifactId>
<scope>runtime</scope>
</dependency>
Remove it once the configuration is updated. The changes most likely to matter:
- MongoDB connection properties such as
spring.data.mongodb.uri,hostanddatabasemoved tospring.mongodb.*. spring.session.redis.*is nowspring.session.data.redis.*.spring-boot-starter-batchnow runs Spring Batch without a database. An application that upgrades without changing its starter stops writing job metadata to the existing tables, so job history and restart data no longer persist. Usespring-boot-starter-batch-jdbcto keep the database-backed job repository.- Liveness and readiness probes are on by default, so the health endpoint exposes those groups.
- Optional Maven dependencies are no longer packaged into uber jars, and the classic uber-jar loader and the embedded launch scripts for fully executable jars were removed.
- War deployments to Tomcat need
spring-boot-starter-tomcat-runtimeinstead ofspring-boot-starter-tomcat.
Also removed in 4.0: Spring Session Hazelcast and Spring Session MongoDB support, now maintained by the Hazelcast and MongoDB teams, auto-configuration for the reactive Pulsar client, and Spock integration, which 4.1 restores.
If you go straight to 4.1
Spring Boot 4.1 removes what 4.0 deprecated, so the deprecated starter names and the Jackson 2 stop-gaps are worth leaving behind during the move rather than after it. 4.1 also removes the layertools jar mode in favour of tools, deprecates Apache Derby support, and stops treating -DskipTests as a reason to skip test AOT processing in the Maven plugin; use maven.test.skip. Its managed jOOQ version, 3.20, needs Java 21. It stays on Spring Framework 7.0 and moves Spring Security to 7.1.
An order of work that keeps a way back
- Move every service to 3.5.16, build with deprecation warnings on, and clear them.
- Replace
javax.annotationandjavax.injectimports, and swap Undertow for Tomcat or Jetty while still on 3.5. - Upgrade one service to Boot 4.1 with the classic starters and the properties migrator. Get it compiling and its tests passing.
- Replace the classic starters with specific ones, paying attention to Flyway, Liquibase, Batch and security test starters.
- Move JSON code to Jackson 3. Where other systems consume the output, compare serialized payloads from the 3.5 and 4.1 builds before release, and use
spring.jackson.use-jackson2-defaultswhere they differ. - Remove the properties migrator, deploy to a canary or a single instance, and watch health, startup logs and error rates.
- Roll out the remaining instances, then the remaining services in dependency order.
Rollback limits. Rolling back an application is a redeploy of the 3.5 artifact, which is why step 1 matters: keep that build current until 4.1 has run in production for a while. Rollback does not undo what the new version wrote. Check three things before calling it safe: JSON written by Jackson 3 to caches, queues or other services, Spring Batch job metadata if the starter changed, and any database migrations Flyway or Liquibase applied on first start.
Where OSSeva fits
Not every application can move before its line runs out. OSSeva for Spring Boot ships patched, signed artifacts for Spring Boot 3.5, which is already past open source support, and for 4.0 after 31 December 2026, delivered through your own Maven or Gradle repository manager, so the 4.1 upgrade can follow your release calendar rather than spring.io's. OSSeva Assure adds an annual architecture review, Java version sequencing and Spring Security reconfiguration guidance. Book a discovery call for a quote. If you are comparing vendors for the gap, see Spring end-of-life support providers.
Frequently asked questions
Does Spring Boot 4 require Java 21?
No. Spring Boot 4.0 and 4.1 require Java 17 or later, and the migration guide encourages the latest LTS. Some managed libraries ask for more: jOOQ 3.20 in Boot 4.1 needs Java 21.
Can I upgrade from Spring Boot 3.3 directly to 4.0?
The release notes strongly recommend upgrading to 3.5 first. 3.5 shows deprecation warnings for everything 4.0 removes, which is the cheapest way to find the code that will break.
Should I upgrade to Spring Boot 4.0 or 4.1?
4.1. Open source support for 4.0 ends on 31 December 2026, and 4.1 is supported until 31 July 2027 on the same Spring Framework 7.0 line.
Why does my Flyway migration not run after upgrading to Spring Boot 4?
Flyway auto-configuration moved into its own module. Add spring-boot-starter-flyway; the same applies to Liquibase with spring-boot-starter-liquibase.
Can I keep using Jackson 2 with Spring Boot 4?
For a transition, yes. Boot keeps dependency management for Jackson 2 and ships a deprecated spring-boot-jackson2 module, but it will be removed in a future release, so plan the move to Jackson 3.
Does Spring Boot 4 support Undertow?
No. Undertow does not yet support Servlet 6.1, so the starter and embedded server support were removed. Use Tomcat, Jetty or Reactor Netty.
What replaces @MockBean in Spring Boot 4?
@MockitoBean, and @MockitoSpyBean replaces @SpyBean.
Tags
Related articles
Apache Camel vs Spring Integration: Differences, When to Use Each and Support Windows
October 8, 2026MigrationMongoDB vs MySQL vs PostgreSQL: Data Model, Transactions, Scaling, Licensing and Which to Choose
October 8, 2026MigrationPostgreSQL vs Aurora PostgreSQL vs RDS: Architecture, Billing, Version Support and When to Self-Manage
October 8, 2026Ready to get your open source under control?
Talk to an OSSeva engineer about CVE coverage, compliance, and migration support for your stack.