DEV Community

Titouan Despierres
Titouan Despierres

Posted on • Originally published at github.com

Spring Boot 4.0 Migration Guide for Production Teams: What Actually Breaks and How to Upgrade Safely

Spring Boot 4.0 Migration Guide for Production Teams: What Actually Breaks and How to Upgrade Safely

Spring Boot 4.0 is not a routine version bump. For most Java teams, it is a platform migration touching Java baseline, Jakarta alignment, dependency graph, packaging behavior, test setup, and especially JSON handling with Jackson 3.

This guide summarizes the official migration notes into a practical, production-focused playbook.

TL;DR

  • Upgrade to the latest 3.5.x first, remove deprecations, then move to 4.0.
  • The biggest migration risks are module/starter changes and Jackson 3 behavior shifts.
  • Use a staged rollout: stabilize with compatibility options, then converge to native Boot 4 patterns.

Why this migration is bigger than usual

Spring Boot 4.0 upgrades major foundations at once:

  • Java baseline: 17+ (latest LTS recommended)
  • Servlet baseline: 6.1
  • Jakarta EE: 11
  • Spring Framework: 7.x
  • Preferred JSON engine: Jackson 3

That means many apps compile but still fail at runtime (serialization contracts, missing transitive dependencies, test infra drift, startup assumptions).

Step 0: Before touching Boot 4

1) Move to latest Boot 3.5.x

Do this first so you are already on the newest dependency line and can clean warnings progressively.

2) Remove 3.x deprecations

Anything deprecated in Boot 3.x is a removal candidate in 4.0.

3) Audit external BOMs and managed libs

If you pin versions outside Boot management (for example Spring Cloud), validate Boot 4 compatibility before upgrading.

4) Re-check environment requirements

  • Java 17+
  • Kotlin 2.2+ (if used)
  • GraalVM 25+ for native-image

Features removed in Boot 4 you must account for

From the migration guide, notable removals include:

  • Undertow support dropped (Servlet 6.1 baseline incompatibility)
  • Pulsar reactive auto-configuration removed
  • Embedded launch scripts for fully executable jars removed
  • Spock integration removed (Groovy 5 gap)
  • Direct Boot support removed for Spring Session Hazelcast/MongoDB integrations

If your runtime or packaging relies on these features, plan alternatives before switching versions.

The biggest structural change: modularization

Boot 4 introduces smaller focused modules and a more consistent starter model.

What changes in practice

  • More technologies now have dedicated starters.
  • Test infra is also modularized with companion test starters.
  • If your app relied on implicit transitive deps, you may now miss required pieces.

Typical example

If you used Flyway/Liquibase only via third-party dependency before, Boot 4 expects explicit Boot starter usage:

  • spring-boot-starter-flyway
  • spring-boot-starter-liquibase

Test side impact

You should depend on technology-specific test starters, not just one global test starter.

For example, security test behavior now expects proper security test starter alignment.

Transition path: classic starters

For teams upgrading a large legacy codebase, Boot 4 provides a temporary bridge:

  • spring-boot-starter-classic
  • spring-boot-starter-test-classic

Use this to restore broad classpath coverage, fix imports/configs, then progressively move to focused starters.

Treat this as transitional, not the end state.

Jackson 3 migration: the highest-risk area

Boot 4 prefers Jackson 3 and introduces major ecosystem changes.

Key changes

  • Group/package migration from com.fasterxml.jackson to tools.jackson (with exceptions)
  • Boot integration class renames for consistency
  • Property namespace changes for JSON-specific read/write settings
  • Automatic registration of all classpath Jackson modules by default

Immediate risks

  • API payload differences (date/time formatting, null/default handling)
  • stricter or different deserialization outcomes
  • polymorphic payload regressions
  • subtle contract breakage across clients

Useful compatibility controls

Boot 4 adds transitional options:

  • spring.jackson.use-jackson2-defaults=true (closer behavior to Boot 3/Jackson 2 defaults)
  • spring-boot-jackson2 module as temporary stop-gap

Use these as migration aids, not long-term architecture.

Other migration changes teams miss

  • JSpecify nullability annotations can affect Kotlin/null-check tooling
  • Logback default charset behavior now aligned with UTF-8 expectations
  • BootstrapRegistry / EnvironmentPostProcessor package moves can break deep integrations
  • PropertyMapper no longer maps null source values by default (use always() when needed)
  • DevTools LiveReload now disabled by default
  • Optional Maven dependencies no longer included by default in uber jars

Recommended production migration strategy

Phase 1 — Stabilize

  1. Upgrade to latest 3.5.x
  2. Remove deprecations
  3. Upgrade to Boot 4 with classic starters
  4. Ensure app starts and core flows run

Phase 2 — Correctness

  1. Add contract tests for JSON payloads
  2. Verify Jackson behavior against real fixtures
  3. Fix dependency graph explicitly (main + test)
  4. Validate startup/runtime with production-like config

Phase 3 — Convergence

  1. Replace classic starters with focused starters
  2. Remove compatibility flags one by one
  3. Re-check observability and actuator behavior
  4. Final cleanup and docs update

CI/CD checks you should add before rollout

  • Dependency diff gate (3.5 vs 4.0)
  • Contract test stage for API payload compatibility
  • Integration tests with representative fixtures
  • Canary rollout + error budget guardrails
  • Fast rollback trigger on error spike

Practical checklist

  • [ ] Latest 3.5.x in production first
  • [ ] No known 3.x deprecations in code paths
  • [ ] Environment meets Java/Jakarta/Servlet requirements
  • [ ] Removed features audited (Undertow, etc.)
  • [ ] Jackson migration strategy selected (native vs transitional)
  • [ ] Starter and test-starter dependencies reviewed
  • [ ] Contract/integration tests green
  • [ ] Canary + rollback plan validated

Final takeaway

Spring Boot 4.0 gives a cleaner long-term model, but migration quality depends on discipline:

  • explicit dependencies,
  • explicit JSON behavior,
  • explicit rollout strategy.

If you treat it as a platform migration instead of a “version bump”, the upgrade is predictable and safe.

Top comments (2)

Collapse
 
shitij_bhatnagar_b6d1be72 profile image
Shitij Bhatnagar

Thanks for the detailed article.

Few points-
1) 'date/time formatting, null/default handling' - the upgrade should be backward compatible, why would this be an issue post the upgrade?
2) Performance impact - what is the impact on memory usage, start up time, response times
3) Many a times in Spring/Boot upgrades, existing components do not get loaded and we need (or needed) to write additional @Config classes to load those components
4) A major impact of the upgrade should be reduction in security vulnerabilities, hope that was seen too

Collapse
 
aytronn profile image
Titouan Despierres • Edited

Yes 👍 super points, thanks!

1) You’re right: upgrade is mostly backward-compatible, but issues usually come from app-specific mapper config + contract assumptions, not Boot alone.
2) Perf impact depends on each app; I recommend before/after measurement (startup, memory, p95 latency) rather than generic numbers.
3) Agreed — with modularization, some components may need explicit starters/config to load correctly.
4) Yes, security posture should improve with newer dependencies, but it’s best validated with a CVE scan before/after.

the entire article is based on the official Spring Boot 4 migration guide published by the Spring team:
Spring Boot 4 migration guide