What's New in Spring Boot 4.0
Spring Boot 4.0 (November 2025) is a major release built on Spring Framework 7 and Java 17+. It’s the most significant Spring release since Boot 3’s Jakarta EE migration. This article covers every change that affects a practicing developer.
Minimum Requirements
| Spring Boot 3.x | Spring Boot 4.0 | |
|---|---|---|
| Java | 17 | 17 (baseline), 21 recommended |
| Spring Framework | 6.x | 7.x |
| Jakarta EE | 10 | 11 |
| Tomcat | 10.x | 11.x |
| Hibernate | 6.x | 7.x |
| Gradle (if used) | 7.x | 8.x |
Java 17 Baseline, Java 21 Recommended
Spring Boot 4 requires Java 17 minimum. But Java 21 is the recommended runtime for new projects:
- Virtual threads are stable (Java 21) and on by default in Spring Boot 4
- Sequenced collections (
SequencedCollection,SequencedMap) are available - Pattern matching for switch is final
- Record patterns are final
- Spring Framework 7 uses Java 21 APIs internally where available
If you’re on Java 17: upgrade works, but you miss virtual threads.
Virtual Threads On by Default
In Spring Boot 3.2+, you had to opt in:
# Boot 3.2 — opt in
spring:
threads:
virtual:
enabled: true
In Spring Boot 4.0, virtual threads are on by default for Tomcat and @Async. No configuration needed. If you need to opt out (e.g., pinning issues with heavily synchronized code):
spring:
threads:
virtual:
enabled: false
JSpecify Null Safety
Spring Framework 7 adopts JSpecify for null safety annotations — the first standardized, tooling-supported null safety for Java APIs.
// Spring Framework 7 APIs are annotated
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import org.jspecify.annotations.NullMarked;
@NullMarked // all APIs in this package are non-null by default
public class OrderService {
public Order findById(UUID id) { // return type is @NonNull
return orderRepository.findById(id).orElseThrow();
}
public @Nullable Order findByIdOrNull(UUID id) { // explicit nullable
return orderRepository.findById(id).orElse(null);
}
}
In your own code: annotate packages with @NullMarked and methods that return null with @Nullable. IntelliJ IDEA and the Kotlin compiler understand JSpecify — you get null safety warnings at compile time.
Jakarta EE 11
Spring Boot 4 moves from Jakarta EE 10 to Jakarta EE 11:
| API | Old | New |
|---|---|---|
| Servlet | 6.0 | 6.1 |
| JPA | 3.1 | 3.2 |
| Bean Validation | 3.0 | 3.1 |
| CDI | 4.0 | 4.1 |
| JSON-B | 3.0 | 3.0 |
JPA 3.2 is the biggest change. Highlights:
find()withTypedQueryReference— compile-safe named queriesCriteriaBuilder.union()— finally, JPQL unionsTableschema generation improvements@Idon records (experimental)
// JPA 3.2: @Id on records (Spring Boot 4 + Hibernate 7)
@Entity
public record OrderItem(
@Id UUID id,
UUID orderId,
UUID productId,
int quantity,
BigDecimal price
) {}
Spring Framework 7 Key Changes
Declarative HTTP Clients (GA)
// Was experimental in Spring 6.1 — GA in Spring 7
@HttpExchange("http://inventory-service/api")
public interface InventoryClient {
@GetExchange("/inventory/{productId}")
Inventory getInventory(@PathVariable UUID productId);
@PostExchange("/reservations")
Reservation reserve(@RequestBody ReservationRequest request);
}
@Bean
InventoryClient inventoryClient(RestClient.Builder builder) {
RestClient restClient = builder.baseUrl("http://inventory-service").build();
RestClientAdapter adapter = RestClientAdapter.create(restClient);
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
return factory.createClient(InventoryClient.class);
}
This is Spring’s native declarative HTTP client — similar to Feign but part of the framework with no additional dependency.
RestClient (Stable Improvements)
// Exchange functions and streaming
restClient.get()
.uri("/api/orders/stream")
.retrieve()
.toEntityFlux(OrderEvent.class) // streaming response
.subscribe(event -> processEvent(event));
Improved AOT (Build-Time) Processing
Spring Framework 7 extends AOT to more scenarios:
- Conditional bean registration is pre-computed at build time
@Profileconditions resolved at build time for native images- Better
@Conditionalsupport without reflection hints
Removed: WebMVC.fn with HandlerFunctions
Spring Framework 7 removes the experimental functional web layer from Spring MVC. Use @RestController or the WebFlux functional API instead.
Hibernate 7 Changes
spring:
jpa:
properties:
hibernate:
# New in Hibernate 7: SQL logging via dedicated logger (not root)
show_sql: false # use logging.level instead
format_sql: true
# Hibernate 7 generates better SQL for complex joins
query:
plan_cache_max_size: 2048
Hibernate 7 improvements:
- Better pagination SQL (fewer subqueries)
@SoftDeleteannotation — soft deletion without custom logic- Better support for
java.timetypes directly in@Column - Embeddable aggregate (JSON column mapping) improvements
// @SoftDelete — Hibernate 7
@Entity
@SoftDelete // adds deleted/deleted_at column, filters all queries automatically
public class Order {
@Id private UUID id;
private OrderStatus status;
// delete() now sets deleted=true, not DELETE FROM orders
}
Spring Security 7
// Deprecated in Security 6, removed in Security 7:
// ❌ Removed
http.antMatcher("/api/**") // use requestMatchers()
http.mvcMatchers("/api/**") // use requestMatchers()
http.authorizeRequests() // use authorizeHttpRequests()
http.csrf().disable() // use csrf(AbstractHttpConfigurer::disable)
// ✓ Current API
http.requestMatchers("/api/**")
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
.csrf(AbstractHttpConfigurer::disable);
PassKeys (WebAuthn) support is GA in Spring Security 7 — passwordless authentication with hardware keys.
Actuator Changes
# New in Boot 4
management:
endpoint:
health:
roles: ACTUATOR_ADMIN # role required for full health details
endpoints:
web:
exposure:
include: health,info,prometheus
# New: structured output format
info:
os:
enabled: true
process:
enabled: true
/actuator/info now includes OS and process information by default — useful for debugging pod-level issues in Kubernetes.
Removed Deprecated APIs
Spring Boot 4 removes APIs deprecated in Boot 3.x:
// ❌ Removed in Boot 4
@SpringBootApplication.exclude() // use @EnableAutoConfiguration(exclude=...)
SpringApplication.setBannerMode(Mode.OFF) // use spring.main.banner-mode=off
TestRestTemplate.withBasicAuth() // use getForEntity with HttpHeaders
// Spring MVC:
ModelAndView(String viewName, ModelMap model) // use Map<String, Object> variant
// Security:
WebSecurityConfigurerAdapter // use SecurityFilterChain beans (removed in Boot 3 too)
Check for deprecation warnings on Boot 3.x before migrating — everything deprecated in 3.x is gone in 4.x.
Dependency Upgrades
<!-- Spring Boot 4 manages these versions automatically -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.0.0</version>
</parent>
<!-- Key managed dependencies -->
<!-- Spring Framework: 7.0.x -->
<!-- Hibernate: 7.0.x -->
<!-- Micrometer: 1.14.x -->
<!-- Resilience4j: 2.3.x -->
<!-- Testcontainers: 1.20.x -->
<!-- Jackson: 2.18.x -->
<!-- Logback: 1.5.x -->
<!-- Netty: 4.2.x -->
What You’ve Learned
- Spring Boot 4 requires Java 17 minimum; Java 21 is recommended for virtual threads
- Virtual threads are on by default — no configuration needed
- JSpecify null safety annotations are adopted across Spring Framework 7 APIs
- Jakarta EE 11 brings JPA 3.2 with
CriteriaBuilder.union()and@SoftDeletein Hibernate 7 - Declarative HTTP clients (
@HttpExchange) are GA — Spring’s native Feign alternative - Spring Security 7 removes deprecated
antMatcher,authorizeRequests, and adds WebAuthn - All APIs deprecated in Boot 3.x are removed — fix deprecation warnings before migrating
Next: Article 56 — Migrating from Spring Boot 3.x to 4.0 — step-by-step migration guide.