Search nomadLab

Spring Boot 3.5 Is Past End of Life: What the 4.0 Migration Actually Breaks

The last open source 3.5 release shipped in June and nothing has followed it. Here is the real list of what changes on the way to 4.x, in the order it will bite you.

Updated

Spring Boot 3.5 reached the end of its open source support window on 30 June 2026. The last community release was 3.5.16 on 25 June, and the release feed has carried nothing for the 3.5 line since. If you are still on it, you are running a version that will not receive a fix for the next CVE unless you are paying for commercial support.

That changes the shape of the decision. This was a scheduling problem in the spring and it is a risk problem now, which usually means it stops competing with feature work for attention and starts competing with incidents.

Release information here was checked against the Spring Boot release feed and the project’s migration guide on 21 August 2026. The current line is 4.1.x, with 4.0.x still receiving patches.

Decide between 4.0 and 4.1 first

There are two supported targets, and picking the wrong one adds a second migration.

4.0 is the version that carries every breaking change described below. 4.1 builds on it and is where the ongoing work is happening. If you are starting the migration now rather than in April, going straight to 4.1 is usually right: the breaking changes are identical, and you land on the line that will keep receiving features rather than only fixes.

Go to 4.0 instead when something you depend on has not certified against 4.1 yet, and treat that as a stop on the way rather than a destination.

Baseline requirements, which gate everything else

Boot 4 requires Java 17 or later, Jakarta EE 11 with Servlet 6.1, Kotlin 2.2 or later for Kotlin projects, and GraalVM 25 or later if you build native images.

The Servlet 6.1 requirement has one casualty worth knowing before you plan anything: Undertow is no longer supported, because it does not implement Servlet 6.1. If your services run on Undertow, your migration includes an application server change, and that is a different size of project than a dependency bump. Find out on day one rather than in week three.

Jackson 3 is the change that touches the most files

Boot 4 defaults to Jackson 3, and Jackson 3 moved its coordinates. The group ID changes from com.fasterxml.jackson to tools.jackson, which means every direct dependency declaration and every exclusion in your build file needs attention, including the ones you inherited from a parent POM years ago.

The renames follow the same pattern. @JsonComponent becomes @JacksonComponent, @JsonMixin becomes @JacksonMixin, JsonObjectSerializer becomes ObjectValueSerializer, and Jackson2ObjectMapperBuilderCustomizer becomes JsonMapperBuilderCustomizer. None of it is conceptually hard. All of it is mechanical work spread across whichever files touch serialization, which in most services is more files than anyone expects.

There is an escape hatch: a deprecated spring-boot-jackson2 module exists so you can stay on Jackson 2 while you migrate everything else. Use it to split the work into two changes rather than one, and then actually come back for the second one.

The modularization, and the starters you now have to name

Boot 4 broke the large auto configuration jars into smaller focused modules. The practical effect is that things which used to arrive implicitly now need an explicit starter: spring-boot-starter-flyway and spring-boot-starter-liquibase are the two that catch most projects, and there are new test starters such as spring-boot-starter-graphql-test.

Some familiar starter names are deprecated in favor of more precise ones, including spring-boot-starter-web in favor of spring-boot-starter-webmvc. Your build still works with the old names for now, and cleaning them up is the sort of task that is much cheaper while you are already in the build file.

Property renames and quiet default changes

OldNew
spring.data.mongodb.*spring.mongodb.*
spring.session.redis.*spring.session.data.redis.*

Two defaults also changed without renaming anything. Logback’s charset is now UTF-8 everywhere, which is almost always what you wanted and is still a change in log output that a downstream parser might notice. DevTools live reload is disabled by default, which surprises exactly one person per team on their first local run.

Tests break in a way that looks like a bug

@MockBean and @SpyBean are gone, replaced by @MockitoBean and @MockitoSpyBean, and the deprecated MockitoTestExecutionListener is removed entirely.

The one that produces the most confusing failures: @SpringBootTest no longer automatically provides MockMVC or TestRestTemplate support. Tests that relied on it compile and then fail at runtime in ways that read like context loading problems rather than missing configuration. If your test suite goes red in a large and incoherent way, start here before debugging anything else.

An order that keeps the work reviewable

Upgrade the JDK and get green on 3.5 first, if you are not already on 17 or later. Mixing a JDK upgrade into a framework migration makes every failure ambiguous.

Move off Undertow next, if you are on it, and release that separately. It is the only step here that is a real architectural change.

Then take 4.x with the Jackson 2 compatibility module in place, fix the build, the starters, the properties, and the tests, and ship that. The diff is large but every piece of it is mechanical, which makes it reviewable.

Drop the Jackson 2 module last, as its own change, so that if serialization behavior shifts anywhere you know exactly which release caused it.

The thing not to do is wait for a quieter quarter. The 3.5 line is not getting security fixes, and the migration does not get cheaper by aging. It gets more expensive, because the dependency versions you are pinned to keep drifting further from what Boot 4 expects.

Keep reading