A Spring Boot 3 to 4 migration should start with a working application on the latest 3.5.x patch. From there, the important work is dependency and package changes, JSON compatibility, security configuration, and tests that exercise real application behavior.

Java 17 remains the minimum for Spring Boot 4.0. You do not have to upgrade to Java 21 just to adopt Boot 4. This guide covers the 3.5-to-4.0 transition; check the release-specific documentation if your target is another Boot line.

Check the Requirements Before Changing Dependencies

According to the Spring Boot 4.0 system requirements, the baseline is Java 17 and Spring Framework 7. Build support includes Maven 3.6.3 or later and Gradle 8.14 or later in the 8.x line, or Gradle 9.x. Native-image builds require GraalVM 25 or later.

Check the JDK actually used by the build, rather than relying on the version installed in your terminal:

java -version
./mvnw -version
# For a Gradle project:
./gradlew --version

Record the versions used in CI, containers, and production too. Keep a separate list of dependencies your team versions outside the Boot dependency management, including Spring Cloud, database drivers, and internal starters.

If you are still on Boot 2, first work through the Spring Boot 2.7 to 3.x migration. Combining that namespace migration with the Boot 4 changes makes failures harder to diagnose.

Step 1: Establish a Spring Boot 3.5 Baseline

Move to the latest available 3.5.x maintenance release, commit the dependency changes, and get the test suite passing. Resolve deprecation warnings before moving to 4.0. This is the upgrade sequence in the official Boot 4 migration guide.

Save representative HTTP responses, database results, authentication flows, and batch restart behavior as regression fixtures. A clean compile is only the first check: changed defaults can alter behavior without producing compiler errors.

Step 2: Update Application and Test Starters

Boot 4 splits support into more focused modules and moves a number of classes into new packages. Review application and test dependencies together. These are examples of the changes to check:

Application concernBoot 4 dependency to review
Spring MVCspring-boot-starter-webmvc
MVC test supportspring-boot-starter-webmvc-test
Security test supportspring-boot-starter-security-test
Flyway migrationsspring-boot-starter-flyway
Liquibase migrationsspring-boot-starter-liquibase
Persistent Spring Batch metadataspring-boot-starter-batch-jdbc

For an MVC application, the relevant Maven fragments are:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webmvc</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webmvc-test</artifactId>
    <scope>test</scope>
</dependency>

Let your chosen Boot parent or BOM manage these versions. The old web starter is deprecated, so its continued availability does not mean your dependency review is finished. Use the official migration guide’s starter tables for the technologies your application uses.

Missing beans or test annotations are a reason to inspect the dependency tree and import packages. Adding unrelated libraries until compilation succeeds can conceal the missing starter.

Step 3: Treat Jackson 3 as a Compatibility Change

Boot 4 prefers Jackson 3. The Jackson 3 migration documentation explains the change from com.fasterxml.jackson to tools.jackson for most packages. Jackson annotations remain under com.fasterxml.jackson.annotation, so a global search-and-replace is inappropriate.

For example, review imports such as:

// Jackson 2
import com.fasterxml.jackson.databind.ObjectMapper;

// Jackson 3
import tools.jackson.databind.ObjectMapper;

Check custom serializers, registered modules, mapper customization, and libraries that expose Jackson types. Then compare JSON fixtures before and after the upgrade: dates, enum values, null fields, error responses, and polymorphic payloads are useful starting points.

Boot’s migration guide also documents renamed customization classes and the temporary Jackson 2 compatibility module. Use that bridge only with an explicit plan to remove it. A project that compiles with both Jackson versions still needs serialization tests.

Step 4: Migrate the Spring Security Configuration

Spring Security 7 removes authorizeRequests and the chained .and() configuration style. Use authorizeHttpRequests with the lambda DSL. The changes are listed in Spring Security 7’s release notes.

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

This fragment shows authorization rules; preserve your application’s authentication configuration alongside them.

CSRF protection was already enabled by default in Spring Security 6. A new 403 is not evidence that Boot 4 suddenly enabled CSRF for REST APIs. Check the selected filter chain, credentials, authorization rules, and token handling. The Spring Security 6.5 CSRF documentation describes the existing behavior.

Keep protection for browser flows that use automatically supplied credentials. In tests, include a valid CSRF token where required and add a negative test for a missing token. Do not disable protection globally just to get the suite passing.

Step 5: Check Changes That Can Survive Compilation

Undertow and Servlet Containers

Boot 4.0 removes Undertow support and requires a Servlet 6.1 container. Change the server dependency and audit its configuration; renaming server.undertow properties does not replace the server. Exercise uploads, timeouts, forwarded headers, and graceful shutdown on the selected server.

Spring Batch Metadata

The regular batch starter uses the new mode without a database. For persistent job metadata, switch to spring-boot-starter-batch-jdbc, then verify restart behavior against the existing database. Merely retaining a datasource does not make this migration complete.

Configuration Properties

Add the properties migrator temporarily while diagnosing renamed or removed settings:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-properties-migrator</artifactId>
    <scope>runtime</scope>
</dependency>

Apply the reported changes to your actual configuration files. Remove the migrator, restart, and rerun the affected tests before release. Its temporary runtime mappings should not become a hidden production dependency.

Persistence and Observability

Hibernate 7 removes save, update, and saveOrUpdate. Review wrappers that still call them before the framework upgrade. Life after saveOrUpdate explains the entity-state decisions and the Envers audit behavior a mechanical replacement can lose.

Verify generated SQL and transaction behavior with your real database engine. Compare the telemetry received by your backend before and after migration: missing traces, changed metric labels, or broken alerts can leave a successful deployment difficult to operate. The OpenTelemetry guide provides a starting point for checking that path.

Use OpenRewrite for the Mechanical Work

The recipe ID is org.openrewrite.java.spring.boot4.UpgradeSpringBoot_4_0. Consult the current recipe documentation for its edition, artifact availability, and repository setup before running it. Do not assume an old plugin version and an unpinned LATEST recipe will reproduce someone else’s migration.

With the appropriate plugin and recipe dependency configured, generate a patch first:

# Maven project with Rewrite configured
./mvnw rewrite:dryRun \
  -Drewrite.activeRecipes=org.openrewrite.java.spring.boot4.UpgradeSpringBoot_4_0

# Or Gradle project with the same recipe configured
./gradlew rewriteDryRun

Review that patch, apply it on a branch, and run the regression suite. Our OpenRewrite walkthrough covers how to organize the migration into reviewable changes.

Migration Checklist

  • Latest selected Boot 3.5 patch passes regression tests before the major upgrade.
  • JDK, build plugins, and independently versioned libraries support the chosen Boot 4 patch.
  • Application and test starters match the technologies in use.
  • Jackson customization and representative JSON contracts pass compatibility tests.
  • Authentication, authorization, and CSRF tests pass for each filter chain.
  • Server behavior, database queries, and batch restart behavior are verified.
  • Properties migrator is removed and the application still starts correctly.
  • Telemetry, health checks, and rollback are exercised in staging.

Benchmark startup, CPU, memory, and latency against your own baseline. This upgrade does not guarantee a percentage improvement, and changing the JDK, framework, collector, and resource limits together makes the result harder to explain.

If you need help assessing dependencies or sequencing the rollout, talk through your migration with Katyella.

Java Modernization Readiness Assessment

15 questions your team should answer before starting a migration. Takes 10 minutes. Could save you months.