Hire Me
← All Writing Spring Boot

Spring Boot 3 Migration Guide — What Changed from 2.x and How to Upgrade

The key breaking changes in Spring Boot 3 — Jakarta namespace, Java 17 baseline, Actuator changes, Spring Security updates — and a practical migration path from Spring Boot 2.x.

Spring Boot 3.0 was a significant version bump: Java 17 is the minimum, the javax namespace became jakarta, Spring Security 6 rewrote its configuration model, and Actuator endpoints changed. The changes are well-defined, but an existing 2.x application has several migration steps before it runs on 3.x. Working through them systematically avoids surprises.

Pre-requisites

  1. Java 17: Boot 3 requires Java 17. If you are on Java 11 or 8, upgrade the JDK first, compile your code with --release 17, and fix any deprecations before touching Boot.

  2. Spring Boot 2.7: Migrate to the latest 2.7.x before jumping to 3.0. Spring Boot 2.7 ships deprecation warnings for APIs removed in 3.0 — they are your to-do list.

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.18</version>   <!-- latest 2.7 first -->
</parent>

Fix all deprecation warnings from the compiler. Then change the version to 3.0.x.

The javax → jakarta namespace change

Every javax.* import that belongs to Jakarta EE (not Java SE) changed to jakarta.*. This is the most widespread change.

// Before
import javax.persistence.Entity;
import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotNull;

// After
import jakarta.persistence.Entity;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.constraints.NotNull;

There are thousands of these in a typical application. Automate the rename with IntelliJ’s “Migrate to Jakarta EE 9” refactoring, or a simple sed script:

find src -name "*.java" -exec sed -i \
  's/import javax\.persistence\./import jakarta.persistence./g;
   s/import javax\.servlet\./import jakarta.servlet./g;
   s/import javax\.validation\./import jakarta.validation./g;
   s/import javax\.annotation\./import jakarta.annotation./g' {} \;

Check for javax in:

Spring Security 6 configuration

Spring Security 6 removed the WebSecurityConfigurerAdapter that most 2.x applications extend:

// Before — adapter style
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/public/**").permitAll()
            .anyRequest().authenticated();
    }
}

// After — component-based
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/public/**").permitAll()
                .anyRequest().authenticated()
            )
            .build();
    }
}

The method chain equivalents:

Actuator endpoint changes

/actuator/health groups are configured differently:

# Before
management.health.probes.enabled: true

# After — same property, but new group names
management.endpoint.health.probes.enabled: true
management.health.livenessstate.enabled: true
management.health.readinessstate.enabled: true

The /actuator/prometheus endpoint requires explicit inclusion in Boot 3:

management:
  endpoints:
    web:
      exposure:
        include: health, info, prometheus, metrics

Spring Data changes

Spring Data JPA 3.x dropped support for Page<T> with @Query count queries that don’t specify countQuery explicitly. Add countQuery to any @Query pagination:

@Query(value     = "SELECT o FROM Order o WHERE o.marketId = :id",
       countQuery = "SELECT COUNT(o) FROM Order o WHERE o.marketId = :id")
Page<Order> findByMarketId(@Param("id") String marketId, Pageable pageable);

Dependency compatibility

Hibernate 6 (the JPA provider) ships with Boot 3. It changed:

Third-party libraries must also be on Jakarta-compatible versions. Check the Spring Boot 3 compatibility matrix for common libraries.

Circulardependency detection

Boot 3 enables circular dependency detection by default — if your application has circular bean dependencies it will fail to start. Fix the circular dependency (usually by introducing an interface or a @Lazy injection). If you genuinely cannot break the cycle immediately:

spring:
  main:
    allow-circular-references: true   # temporary — fix properly

Property changes

Several property keys were deprecated in 2.7 and removed in 3.0. Run your application with Boot 2.7 and look for DeprecatedPropertiesDetector warnings in the logs. Common ones:

# Removed in Boot 3 — use the replacement
spring.redis.*       → spring.data.redis.*
spring.datasource.initialization-mode → spring.sql.init.mode
logging.file         → logging.file.name

Testing changes

@SpringBootTest defaults for properties changed. If your tests rely on the old test property resolution order, review @TestPropertySource and @DynamicPropertySource usage.

MockMvc is auto-configured in @WebMvcTest without any change — the configuration model carries over.

Migration checklist

If you’re migrating a Spring Boot 2.x service to Boot 3 and want help with the migration plan, get in touch.

Samuel Jackson

Samuel Jackson

Senior Java Back End Developer & Contractor

Senior Java Back End Developer — Betfair Exchange API specialist, Spring Boot, AWS, and event-driven architecture. 20+ years delivering high-performance systems across betting, finance, energy, retail, and government. Available for Java contracting.