Spring Boot 4.0 is the most significant update since the jump to Spring Boot 3.0. It requires Spring Framework 7.0, Java 17 as the minimum (with full support for Java 21+), and introduces important breaking changes alongside new capabilities that simplify API development, observability, and testing. This guide covers the most relevant new features and how to migrate from 3.x.
Prerequisites
Spring Boot 4.0 raises the minimum versions across the entire ecosystem:
| Dependency | Minimum version |
|---|---|
| Java | 17 (21+ recommended) |
| Spring Framework | 7.0 |
| Spring Security | 7.0 |
| Jackson | 3.0 |
| Hibernate | 7.1 |
| Tomcat | 11.0 |
| Gradle | 8.14+ / 9.x |
// build.gradle.kts
plugins {
id("org.springframework.boot") version "4.0.6"
id("io.spring.dependency-management") version "1.1.7"
kotlin("jvm") version "2.1.0"
kotlin("plugin.spring") version "2.1.0"
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
HTTP Service Clients: REST Without Boilerplate
One of the most anticipated new features. Spring Boot 4.0 auto-configures implementations of interfaces annotated with @HttpExchange, eliminating the need to manually implement REST clients.
// Define the interface — Spring generates the implementation
@HttpExchange("https://api.github.com")
public interface GitHubClient {
@GetExchange("/users/{username}")
GitHubUser getUser(@PathVariable String username);
@GetExchange("/repos/{owner}/{repo}")
GitHubRepo getRepo(@PathVariable String owner, @PathVariable String repo);
}
// Register the client as a bean
@Configuration
public class ClientConfig {
@Bean
public GitHubClient gitHubClient(RestClient.Builder builder) {
var restClient = builder.baseUrl("https://api.github.com").build();
var factory = HttpServiceProxyFactory.builderFor(RestClientAdapter.create(restClient)).build();
return factory.createClient(GitHubClient.class);
}
}
// Inject and use directly
@Service
public class GitHubService {
private final GitHubClient client;
public GitHubUser getUserInfo(String username) {
return client.getUser(username); // HTTP call managed automatically
}
}
Built-in API Versioning for Spring MVC and WebFlux
Spring Boot 4.0 adds auto-configuration for API versioning without external libraries:
# application.yml
spring:
mvc:
apiversion:
enabled: true
default-version: "1"
supported-versions: "1,2"
header-name: "X-API-Version" # by header
# param-name: "api-version" # or by query param
# media-type-prefix: "application/vnd.myapp.v" # or by media type
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping
@ApiVersion("1")
public List<UserV1Dto> getUsersV1() {
return userService.findAllV1();
}
@GetMapping
@ApiVersion("2")
public List<UserV2Dto> getUsersV2() {
return userService.findAllV2(); // Enriched response in V2
}
}
OpenTelemetry Starter: Observability Out of the Box
New dedicated starter that auto-configures the OpenTelemetry SDK and exports metrics and traces via OTLP:
// build.gradle.kts
dependencies {
implementation("org.springframework.boot:spring-boot-starter-opentelemetry")
}
# application.yml — just define the endpoint
management:
opentelemetry:
resource-attributes:
service.name: "my-service"
service.version: "4.0.6"
otlp:
endpoint: "http://otel-collector:4318"
export:
traces: true
metrics: true
logs: true
No more manual OpenTelemetry SDK configuration — Spring Boot handles it together with the Micrometer integration.
Virtual Threads with JDK HttpClient
Spring Boot 4.0 leverages Virtual Threads (Project Loom) in more places. The JDK HttpClient now uses them automatically when enabled:
spring:
threads:
virtual:
enabled: true # Enables Virtual Threads across the application
// This synchronous code now scales like reactive
@Service
public class ExternalApiService {
private final GitHubClient gitHubClient;
// Each call runs on a Virtual Thread — no thread pool blocking
public List<GitHubUser> getTeamMembers(List<String> usernames) {
return usernames.parallelStream()
.map(gitHubClient::getUser)
.toList();
}
}
Important Breaking Changes
Jackson 3.0
Jackson 3.0 removes some deprecated APIs. Jackson 2 support exists but in deprecated form:
// build.gradle.kts — if you depend on Jackson 2 APIs, upgrade to Jackson 3
dependencies {
// Jackson 3 is included with Spring Boot 4.0
// If you have direct Jackson 2 dependencies, update them:
implementation("com.fasterxml.jackson.core:jackson-databind:3.0.2")
}
Renamed Properties
Add spring-boot-properties-migrator temporarily to detect deprecated properties:
dependencies {
runtimeOnly("org.springframework.boot:spring-boot-properties-migrator")
}
Most common renames:
| Old property | New property |
|---|---|
management.tracing.enabled | management.tracing.export.enabled |
spring.dao.exceptiontranslation.enabled | spring.persistence.exceptiontranslation.enabled |
Some server.error.* properties | moved to root level |
Auto-Configuration: Public API Removed
Public members of auto-configuration classes have been removed. If you extended or referenced classes like DataSourceAutoConfiguration directly, you need to refactor:
// ❌ No longer compiles in Spring Boot 4.0
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
DataSourceAutoConfiguration.SomeMember member = ...;
// ✅ Use the configured beans directly
@Autowired
DataSource dataSource;
Improved Testing: @MockitoBean and RestTestClient
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class UserControllerTest {
@MockitoBean // Definitively replaces @MockBean
private UserService userService;
@Autowired
private RestTestClient restTestClient; // New in Spring Boot 4.0
@Test
void shouldReturnUser() {
when(userService.findById(1L)).thenReturn(mockUser());
restTestClient.get()
.uri("/api/users/1")
.exchange()
.expectStatus().isOk()
.expectBody(UserDto.class)
.value(user -> assertThat(user.name()).isEqualTo("Test"));
}
}
Console Logging Control
New property for environments where you only want file logging:
logging:
console:
enabled: false # Disables console output — useful in production
file:
name: /var/log/app.log
Migration Checklist from 3.x
- Update Java to 17 minimum (21 recommended)
- Add
spring-boot-properties-migratorand run the app — review the warnings - Update Jackson to 3.x if you have direct dependencies
- Replace
@MockBeanwith@MockitoBeanacross all tests - Review auto-configurations you extend or that reference internal classes
- Migrate to OpenTelemetry Starter if you use Zipkin/Jaeger manually
- Test in staging with production-like traffic before migrating
Conclusion
Spring Boot 4.0 consolidates the modernization of the Spring ecosystem: less boilerplate for HTTP clients, built-in API versioning, OpenTelemetry observability from day one, and Virtual Threads in more application layers. Migration from 3.x requires attention to breaking changes, but the properties-migrator and deprecation messages guide the process clearly.