Home / Spring Boot / Production and Testing / Upgrading Spring Boot: 2.x to 3.x to 4.x

Upgrading Spring Boot: 2.x to 3.x to 4.x

Upgrades are a normal part of a Spring Boot project because each minor version has limited support. Success comes from upgrading in small steps, with tests, using the official tools. This page is a practical checklist for the two big jumps.

Strategy

Boot 2.7.x ──► latest 3.x (3.5.x) ──► 4.x
   Step 1: upgrade to the LAST 2.7.x, remove all deprecation warnings
   Step 2: move to Java 17+, then to Boot 3.0 ... 3.5 (fix jakarta.* and library versions)
   Step 3: on the last 3.5.x remove deprecations that Boot 4 removes
   Step 4: switch to Boot 4.x, one module at a time if needed (classic starters help)
   Each step: green tests, deploy, observe. Never mix a framework upgrade with feature work.

Tools

# 1. Automated code migration with OpenRewrite (free recipes)
mvn -U org.openrewrite.maven:rewrite-maven-plugin:run \
  -Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-spring:RELEASE \
  -Drewrite.activeRecipes=org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_5

# 2. Detect renamed or removed properties while running
#    add temporarily:
#    <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-properties-migrator</artifactId><scope>runtime</scope></dependency>

Use the official migration guides on the Spring Boot GitHub wiki for each version (Spring-Boot-3.0-Migration-Guide and the 4.0 guide), and read the release notes of every minor version you cross.

Boot 2.x to 3.x checklist

AreaChangeAction
JavaJava 17 is the minimumUpgrade the JDK and CI images
Jakarta EEjavax.* packages became jakarta.* (Servlet, JPA, Validation)Replace imports (OpenRewrite does it). Upgrade libraries that use javax
Spring Security 6WebSecurityConfigurerAdapter removed, authorizeRequests replacedUse SecurityFilterChain beans and authorizeHttpRequests with the lambda DSL
Auto-configuration registrationspring.factories replaced by AutoConfiguration.importsMove entries for your own auto-configurations
Hibernate 6Different SQL generation, id generation defaults, removed @Type usages, dialect changesRun all repository tests against the real database
Trailing slash matching/users/ no longer matches /usersFix clients or add explicit mappings
Actuator and metricsMicrometer changes, Prometheus endpoint detailsRecheck dashboards
PropertiesSeveral renamed (e.g. spring.redis.* to spring.data.redis.*)Use the properties migrator
HttpClient and RestTemplateApache HttpClient 5 replaces 4Update dependencies
LoggingDefault log pattern changed slightlyCheck parsers and alerts

Boot 3.x to 4.x checklist

AreaChangeAction
BaselineSpring Framework 7, Jakarta EE 11, Java 17 minimum (21+ recommended)Check servlet container version (Tomcat 11)
Modular code baseAuto-configuration split into smaller modules, starters renamed (for example spring-boot-starter-web to spring-boot-starter-webmvc)Generate a fresh pom from start.spring.io and compare. Classic starters can ease the move
Jackson 3Default JSON library. Packages tools.jackson.*, unchecked exceptions, @JsonComponent replaced by @JacksonComponentUpdate custom serializers and modules. Jackson 2 support can be kept temporarily
Testing@MockBean and @SpyBean removed in favor of @MockitoBean and @MockitoSpyBean. Test slice annotations moved to modular packagesUpdate imports and dependencies (modular test starters)
Null-safetyJSpecify annotations across the portfolioOptional: better IDE and Kotlin checks
Removed deprecated APIsThings deprecated in 3.x are removedFix all deprecation warnings on 3.5 first
Third-party librariesspringdoc, Resilience4j, Spring Cloud, Lombok need Boot 4 compatible versionsCheck compatibility tables before upgrading
New featuresAPI versioning, resilience annotations (@Retryable, @ConcurrencyLimit), HTTP service clients improvementsAdopt after the upgrade is stable

Typical code changes

// Boot 2 -> 3: imports
// before: import javax.persistence.Entity;   javax.validation.Valid;   javax.servlet.http.HttpServletRequest;
// after : import jakarta.persistence.Entity; jakarta.validation.Valid; jakarta.servlet.http.HttpServletRequest;

// Spring Security 5 style (removed)
// @Configuration public class Sec extends WebSecurityConfigurerAdapter {
//     protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().anyRequest().authenticated(); } }

// Spring Security 6 style
@Configuration
@EnableWebSecurity
public class Sec {
    @Bean
    SecurityFilterChain chain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(a -> a.anyRequest().authenticated());
        return http.build();
    }
}

// Boot 3 -> 4 tests
// before: @MockBean OrderService service;
// after : @MockitoBean OrderService service;   (org.springframework.test.context.bean.override.mockito.MockitoBean)

Rollout plan

Common mistake: Jumping straight from Boot 2.5 to 4.0 in one commit. Too many changes at once make failures impossible to locate. Go through the latest release of each major line, and keep every step deployable.

Interview questions

Why can't I just change the version number?

Because packages, defaults and libraries changed (javax to jakarta, Hibernate 6, Security 6, Jackson 3). Code and configuration must be migrated, and third-party libraries must support the new baseline.

How long is a Spring Boot version supported?

Open source support for a minor version is about 12 months, with commercial support longer. Plan regular upgrades every 6 to 12 months to avoid a painful big jump.

What is the safest way to find breaking changes?

Upgrade in small steps, run the properties migrator, use OpenRewrite recipes, read the migration guide, and rely on a good automated test suite.