Spring Boot 4 New Features: What's New in Boot 4 and Spring Framework 7 (+ Interview Questions)
Every Spring Boot 4 change that matters: API versioning, HTTP service clients, @Retryable, JSpecify, Jackson 3, modular starters, a 3.5 to 4.x migration checklist and 15 interview questions.
New21 min read

Spring Boot 4 new features fall into three groups: a new platform (Spring Framework 7, Jakarta EE 11, Jackson 3), features you will use every day (built-in API versioning, HTTP service clients, @Retryable in the core framework, JSpecify null safety), and a reorganized codebase with one module and one starter per technology. This guide explains each change with working code, shows what was removed, and walks through a migration from Spring Boot 3.5.
It is written for Java developers who run Spring Boot 3 in production and want to know what the upgrade costs, and for anyone preparing for interviews in 2026, where "what changed in Spring Boot 4?" has become a standard opening question. Every feature below was checked against the official Spring release notes and reference docs as of October 2026, when Spring Boot 4.1.2 is the current release.
The last part of the guide is 15 Spring Boot 4 interview questions with short, direct answers you can say out loud.
In this guide
- Spring Boot 4 at a glance: versions, dates and the 3 vs 4 comparison
- What's new in Spring Boot 4 and Spring Framework 7
- What changed again in Spring Boot 4.1
- What was removed or deprecated
- Spring Boot 4 migration: a step-by-step checklist
- Spring Boot 4 interview questions
- FAQ
Spring Boot 4 at a glance
Spring Boot 4.0 shipped on 20 November 2025, built on Spring Framework 7.0. Spring Boot 4.1 followed on 10 June 2026, and 4.2 is planned for November 2026 (its first release candidate is already out). Open-source support for the Spring Boot 3.5 line ended on 30 June 2026, so a team still on 3.x now gets security fixes only through commercial support. That date is why so many teams are migrating this year.
Here is the short version of what is different between Spring Boot 3.5 and Spring Boot 4.
- Java: both need Java 17 or later. Spring Framework 7 recommends Java 25, the current LTS.
- Framework: Spring Framework 6.2 in Boot 3.5, Spring Framework 7.0 in Boot 4.
- Jakarta EE: EE 10 with Servlet 6.0 in Boot 3; EE 11 with Servlet 6.1 in Boot 4.
- JSON: Jackson 2 (
com.fasterxml.jackson) in Boot 3; Jackson 3 (tools.jackson) in Boot 4. - Null safety: Spring's own JSR 305-style annotations in Boot 3; JSpecify annotations in Boot 4.
- API versioning: hand-rolled in Boot 3; built into Spring MVC and WebFlux in Boot 4.
- Retry: the separate Spring Retry library in Boot 3;
@RetryableandRetryTemplatein the core framework in Boot 4. - Starters: one large auto-configuration jar in Boot 3; one module and one starter per technology in Boot 4.
- Servers: Tomcat, Jetty and Undertow in Boot 3; Tomcat 11 and Jetty 12.1 in Boot 4 (Undertow dropped).
- Test mocks:
@MockBeandeprecated in Boot 3.4 and 3.5; removed in Boot 4 in favor of@MockitoBean.
What's new in Spring Boot 4 and Spring Framework 7
Java 17 baseline, Java 25 recommended
A common myth is that Spring Boot 4 requires Java 21 or 25. It does not. The minimum is still Java 17, the same as Spring Boot 3. What changed is the recommendation: Spring Framework 7 recommends JDK 25, and some features only light up on newer JDKs. For example, Spring Framework 7 reads class metadata with the Class-File API (JEP 484) when the application runs on Java 24 or later. GraalVM native images need GraalVM 25, and Kotlin projects need Kotlin 2.2.
If you are already on Java 21, nothing forces you to move. If you are choosing today, pick Java 25: it is the current LTS and the version the Spring team tests most heavily against.
Jakarta EE 11 and Servlet 6.1
Spring Boot 4 moves to Jakarta EE 11. In practice that means Servlet 6.1 (Tomcat 11, Jetty 12.1), Jakarta Persistence 3.2 (Hibernate ORM 7.x), and Bean Validation 3.1 (Hibernate Validator 9). Unlike the Boot 2 to Boot 3 move, there is no package rename this time: everything stays in jakarta.*. The visible effects are new versions of Hibernate and your servlet container, plus the loss of Undertow, which does not support Servlet 6.1 yet.
Spring Framework 7 also stopped recognizing the old javax.annotation and javax.inject annotations. If an old library or module still uses @javax.annotation.PostConstruct or @javax.inject.Inject, Spring now ignores it silently. Search your codebase for javax.annotation and javax.inject before you upgrade.
Modular auto-configuration and starters
This is the biggest structural change in Spring Boot 4. In Boot 3, a single spring-boot-autoconfigure jar contained auto-configuration for almost every technology Spring Boot supports. In Boot 4 that code is split into focused modules named spring-boot-<technology>, each with its own root package (org.springframework.boot.<technology>), its own starter, and a matching test starter.
Three consequences matter in day-to-day work:
- Some starters were renamed.
spring-boot-starter-webis nowspring-boot-starter-webmvc,spring-boot-starter-aopis nowspring-boot-starter-aspectj, and the OAuth2 starters moved underspring-boot-starter-security-oauth2-*. The old names still exist for now but are deprecated. - Technologies that never needed a starter now do. In Boot 3, adding
liquibase-coreorflyway-corewas enough. In Boot 4 you addspring-boot-starter-liquibaseorspring-boot-starter-flyway, or the migrations simply do not run. - Tests get their own starters.
spring-boot-starter-webmvc-test,spring-boot-starter-data-jpa-test,spring-boot-starter-security-testand so on. Each one pulls inspring-boot-starter-test, so you list the technologies under test instead.
A Boot 4 web service with JPA and Liquibase therefore looks like this:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-liquibase</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webmvc-test</artifactId>
<scope>test</scope>
</dependency>For a quick first compile during an upgrade, Spring Boot offers spring-boot-starter-classic and spring-boot-starter-test-classic, which put all modules back on the classpath. Treat them as scaffolding: use them to get green, then replace them with the specific starters.
JSpecify null safety
Spring Framework 7 and Spring Boot 4 annotate their APIs with JSpecify annotations instead of Spring's older JSR 305-based org.springframework.lang.Nullable. JSpecify is a standard agreed by several vendors, it can express nullness of generic types, arrays and varargs, and Kotlin and tools such as NullAway understand it.
The usual pattern is to declare a whole package non-null by default and mark the exceptions:
// src/main/java/com/example/orders/package-info.java
@NullMarked
package com.example.orders;
import org.jspecify.annotations.NullMarked;package com.example.orders;
import org.jspecify.annotations.Nullable;
public class OrderService {
// Non-null by default: callers can rely on a value
public Order place(Cart cart) { ... }
// Explicitly nullable: callers must handle "not found"
public @Nullable Order findByReference(String reference) { ... }
}JSpecify is already on your classpath, because spring-core depends on it. The annotations are type-use annotations, so placement matters for arrays: @Nullable String[] means the elements may be null, and String @Nullable [] means the array itself may be null. On its own the annotation changes nothing at runtime. The value comes from IDE warnings and build-time checkers such as NullAway, which turn a NullPointerException in production into a compile error.
First-class API versioning
Before Spring Framework 7, every team versioned REST APIs its own way: /v1 and /v2 URL prefixes, custom headers checked in interceptors, or produces media types. Spring Boot 4 makes versioning a built-in part of request mapping, in both Spring MVC and WebFlux, with support on the client and in tests too.
You choose where the version comes from (a header, a query parameter, a path segment or a media type parameter) once, in configuration:
spring:
mvc:
apiversion:
use:
header: API-Version
supported: 1.0, 1.2, 1.3, 2.0Then controller methods declare which versions they serve with the new version attribute:
@RestController
@RequestMapping("/accounts")
class AccountController {
@GetMapping(path = "/{id}", version = "1.0")
AccountV1 getV1(@PathVariable long id) { ... }
@GetMapping(path = "/{id}", version = "1.2+") // 1.2 and every supported version above it
AccountV2 getV1_2(@PathVariable long id) { ... }
@GetMapping(path = "/{id}", version = "2.0")
AccountV3 getV2(@PathVariable long id) { ... }
}A fixed version such as "1.0" matches only that version. A baseline version such as "1.2+" matches 1.2 and every supported version above it, until a more specific mapping takes over. When several methods match, Spring picks the highest version that is not above the requested one.
The rules worth remembering:
- A version that is not supported causes an
InvalidApiVersionExceptionand a 400 response. - By default a version is required once versioning is enabled; a missing version gives
MissingApiVersionExceptionand a 400. You can make it optional withspring.mvc.apiversion.required=falseand setspring.mvc.apiversion.default. - Supported versions are detected from your mappings by default (
spring.mvc.apiversion.detect-supported), and you can add more explicitly. - To retire a version, an
ApiVersionDeprecationHandler(the built-in one isStandardApiVersionDeprecationHandler) can addDeprecation,SunsetandLinkheaders to responses, as defined in RFC 9745 and RFC 8594.
If you prefer Java configuration over properties, implement configureApiVersioning in a WebMvcConfigurer:
@Configuration
class WebConfig implements WebMvcConfigurer {
@Override
public void configureApiVersioning(ApiVersionConfigurer configurer) {
configurer.useRequestHeader("API-Version");
}
}On the client side, RestClient and WebClient can send the version for you:
RestClient accounts = RestClient.builder()
.baseUrl("https://accounts.internal")
.defaultApiVersion("1.2")
.apiVersionInserter(ApiVersionInserter.useHeader("API-Version"))
.build();Individual requests can override it with .apiVersion("2.0") on the request spec.
HTTP service clients with @ImportHttpServices
Declarative HTTP interfaces (@HttpExchange, @GetExchange, @PostExchange) arrived in Spring Framework 6, but each one needed a hand-written HttpServiceProxyFactory bean. Spring Framework 7 adds @ImportHttpServices, and Spring Boot 4 auto-configures it, so an interface becomes an injectable client with one annotation and a property.
public interface PaymentGatewayClient {
@GetExchange("/payments/{id}")
PaymentStatus status(@PathVariable String id);
@PostExchange("/payments")
PaymentStatus create(@RequestBody CreatePaymentRequest request);
}
@SpringBootApplication
@ImportHttpServices(group = "payments", types = PaymentGatewayClient.class)
public class ShopApplication {
public static void main(String[] args) {
SpringApplication.run(ShopApplication.class, args);
}
}spring:
http:
serviceclient:
payments:
base-url: https://api.payments.example.comClients are organized in groups. Every interface in a group shares one underlying RestClient configuration: base URL, default headers, timeouts, SSL bundle and API versioning, all settable under spring.http.serviceclient.<group>. Interfaces imported without a group land in a group called default. You can also scan a package with basePackages instead of listing types. The Spring Boot reference has the full list of group properties.
Resilience built in: @Retryable and @ConcurrencyLimit
For years, retry in Spring meant adding the separate Spring Retry project. Spring Framework 7 merged a trimmed-down version into the core: RetryTemplate and RetryPolicy in org.springframework.core.retry, and the @Retryable and @ConcurrencyLimit annotations in org.springframework.resilience.annotation. You turn them on with @EnableResilientMethods.
@Configuration
@EnableResilientMethods
class ResilienceConfig {
}
@Service
class InvoiceMailer {
// 1 attempt + up to 4 retries: 200 ms, 400 ms, 800 ms, 1600 ms (capped at maxDelay)
@Retryable(includes = MailSendException.class, maxRetries = 4,
delay = 200, multiplier = 2, maxDelay = 2000)
public void send(Invoice invoice) { ... }
// At most 10 threads inside this method at the same time
@ConcurrencyLimit(10)
public byte[] renderPdf(Invoice invoice) { ... }
}Facts interviewers like to probe, all from the resilience chapter of the Spring docs:
- With no attributes,
@Retryableretries on any exception, up to 3 retries after the first failure, 1 second apart. When retries run out, the last exception is thrown to the caller. - It also has
jitter,excludesand a custompredicate, and it works on reactive methods by decorating the returnedMonoorFlux. - Retry always wraps
@Transactional, so each attempt runs in a fresh transaction. That is the behavior you want: a failed attempt rolls back before the next one starts. @ConcurrencyLimitprotects a resource from too many concurrent callers. It matters most with virtual threads, where there is no thread pool size left to act as a natural limit.
There is no circuit breaker in Spring Framework 7. For that you still use Resilience4j or Spring Cloud Circuit Breaker.
Jackson 3 by default
Spring Boot 4 uses Jackson 3 as its JSON library. The biggest visible change is the package: Jackson 3 lives in tools.jackson, not com.fasterxml.jackson. The one exception is the annotations module, which keeps its old package so @JsonProperty and @JsonIgnore imports still compile.
// Spring Boot 3 (Jackson 2)
import com.fasterxml.jackson.databind.ObjectMapper;
// Spring Boot 4 (Jackson 3)
import tools.jackson.databind.SerializationFeature;
import tools.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.annotation.JsonProperty; // annotations keep their package
import org.springframework.boot.jackson.autoconfigure.JsonMapperBuilderCustomizer;
@Bean
JsonMapperBuilderCustomizer jsonCustomizer() { // was Jackson2ObjectMapperBuilderCustomizer
return builder -> builder.enable(SerializationFeature.INDENT_OUTPUT);
}Other details to know:
- In Jackson 3 the mapper is immutable and built with
JsonMapper.builder(). Spring Boot auto-configures aJsonMapper. To replace it, define your ownJsonMapperbean; anObjectMapperbean is no longer enough. @JsonComponentand@JsonMixinbecame@JacksonComponentand@JacksonMixin.- Jackson 3 changes some defaults. One that bites tests is alphabetical property ordering for regular classes (records keep their component order), which breaks assertions that compare raw JSON strings. Setting
spring.jackson.use-jackson2-defaults=truegives you defaults close to Spring Boot 3 while you migrate. - If a library still needs Jackson 2, Spring Boot 4.0 ships a deprecated
spring-boot-jackson2module as a stop-gap. Spring Framework's current plan is to stop auto-detecting Jackson 2 in 7.1 and remove its support in 7.2, so treat it as temporary.
Programmatic bean registration with BeanRegistrar
@Bean methods register exactly one bean each. When you need to register several beans in a loop, or decide at runtime which beans to create, Spring Framework 7 offers the BeanRegistrar contract:
class NotificationChannelsRegistrar implements BeanRegistrar {
@Override
public void register(BeanRegistry registry, Environment env) {
registry.registerBean("emailChannel", EmailChannel.class);
if (env.matchesProfiles("sms")) {
registry.registerBean("smsChannel", SmsChannel.class,
spec -> spec.lazyInit().description("SMS via provider API"));
}
}
}
@Configuration
@Import(NotificationChannelsRegistrar.class)
class NotificationConfig {
}Most applications will never need it, but it is a good interview topic because it shows you know where @Bean stops being enough.
Testing changes
@MockBeanand@SpyBeanare gone. Use@MockitoBeanand@MockitoSpyBeanfrom Spring Framework. They work on test class fields but not inside@Configurationclasses.@SpringBootTestno longer sets up MockMvc orTestRestTemplateon its own. Add@AutoConfigureMockMvc,@AutoConfigureTestRestTemplateor@AutoConfigureRestTestClient.RestTestClientis new: a non-reactive version ofWebTestClientthat can bind to a controller, an application context or a live server.- JUnit 4 support in the Spring TestContext Framework (
SpringRunner) is deprecated; use JUnit Jupiter.
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureRestTestClient
class AccountApiTests {
@Autowired
RestTestClient client;
@MockitoBean
PaymentGatewayClient gateway;
@Test
void returnsVersion2Account() {
client.get().uri("/accounts/42")
.header("API-Version", "2.0")
.exchange()
.expectStatus().isOk();
}
}Smaller changes worth knowing
JmsClient: a fluent JMS API in the style ofJdbcClientandRestClient, auto-configured by Boot.- OpenTelemetry starter:
spring-boot-starter-opentelemetryexports metrics and traces over OTLP. RestTemplate: deprecated in the Spring Framework 7 reference docs, with a formal@Deprecatedplanned for 7.1. New code should useRestClient.HttpHeaders: no longer extendsMultiValueMap, which breaks code that treated headers as a map.Optionalin SpEL: the null-safe and Elvis operators now unwrapOptional.- Logging:
spring-jclis replaced by Apache Commons Logging 1.3, which should be invisible to most apps.
What changed again in Spring Boot 4.1
If you are starting a migration now, you will land on 4.1, not 4.0. Spring Boot 4.1 (June 2026) added a few features and, importantly, removed everything that was deprecated in 4.0:
- Classes, methods and properties deprecated in 4.0 are removed, so fix deprecation warnings on 4.0 before moving to 4.1.
- Spring gRPC support for servers and clients.
- Server-side request forgery (SSRF) protection for HTTP clients: an
InetAddressFiltercan block outgoing calls to chosen addresses. - Most standard OpenTelemetry environment variables are now read, plus a
management.opentelemetry.enabledswitch. - The
layertoolsjar mode is gone; use thetoolsjar mode for layered Docker images. - Kotlin 2.3, and a jOOQ baseline of 3.20, which requires Java 21 or later if you use jOOQ.
What was removed or deprecated in Spring Boot 4
- Undertow: no starter and no embedded support until Undertow supports Servlet 6.1.
- Everything deprecated in Spring Boot 3.x: removed in 4.0. This is why upgrading to the latest 3.5.x and clearing warnings comes first.
- Executable jar launch scripts: the "fully executable" jar trick for Unix init systems is gone. Use
java -jar. - Reactive Pulsar, Spring Session Hazelcast and MongoDB, and the Spock integration: removed from Boot itself.
- Spring Retry dependency management: removed. If you still use Spring Retry you must pin a version, or move to the core
@Retryable. javax.annotation/javax.inject: no longer recognized by Spring Framework 7.- Path matching options: suffix pattern matching (
/orders.json) and thetrailingSlashMatchoption, both off by default since Spring Framework 6, were removed completely. - Deprecated: Jackson 2 support,
RestTemplate(docs), JUnit 4 support,AntPathMatcher-based request matching, and Boot'sHttpMessageConverterstype.
Spring Boot 4 migration: a step-by-step checklist
The official migration guide is long. This is the order that keeps each step small and testable.
- Upgrade to the latest Spring Boot 3.5.x and fix every deprecation warning. Anything deprecated in 3.x does not exist in 4.0.
- Check the stack. Java 17 or later (25 is the best target). Find the 4.x-compatible versions of libraries Boot does not manage, such as Spring Cloud and springdoc-openapi.
- Bump the Boot version and add
spring-boot-properties-migratorat runtime scope. At startup it prints every renamed property and maps it temporarily. - Fix the starters. If the build breaks badly, add the classic starters first, get to green, then replace them with specific starters. Add the Flyway or Liquibase starter if you use either.
- Move to Jackson 3. Update imports from
com.fasterxml.jacksontotools.jackson(annotations stay), rename customizers, and usespring.jackson.use-jackson2-defaultsif JSON output changes break clients. - Fix the tests.
@MockBeanto@MockitoBean, add@AutoConfigureMockMvcwhere tests use MockMvc, and switch to the-teststarters. - Clean up. Remove the properties migrator and classic starters, run the full suite, deploy to a test environment, then move to the latest 4.1.x.
<!-- temporary, remove after the migration -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-properties-migrator</artifactId>
<scope>runtime</scope>
</dependency>TechTriber's own backend runs Spring Boot 4.1 on Java 25: a multi-module Maven build with Liquibase migrations and Testcontainers integration tests. If your project has the same shape, give two items extra attention. First, every module that runs Liquibase needs spring-boot-starter-liquibase, or your schema changes stop applying without an error. Second, integration tests that relied on @SpringBootTest providing MockMvc or TestRestTemplate need the new @AutoConfigure... annotations. Run the integration tests, not just the unit tests, before you call the upgrade done.
Tip: do the Spring Boot upgrade and the Java upgrade as two separate changes. If something breaks, you will know which one caused it.
Spring Boot 4 interview questions
These are the questions that come up when an interviewer wants to know whether you have actually worked with Spring Boot 4 or only read the headline. Each answer starts with the version you can say in an interview, followed by detail for follow-ups.
What is the minimum Java version for Spring Boot 4?
Java 17, the same as Spring Boot 3. Spring Framework 7 recommends Java 25, the current LTS, and some features use newer JDK APIs when available, such as the Class-File API on Java 24+. GraalVM native images need GraalVM 25, and Kotlin projects need Kotlin 2.2 or later.
What is the difference between Spring Boot 3 and Spring Boot 4?
Spring Boot 4 moves to Spring Framework 7, Jakarta EE 11 (Servlet 6.1) and Jackson 3. It splits auto-configuration into a module per technology, adds built-in API versioning, HTTP service client auto-configuration and core retry annotations, and adopts JSpecify for null safety. It also removes Undertow and everything deprecated in 3.x.
What the interviewer is checking: whether you can name concrete changes rather than "it is faster and better". Three specific items with one sentence each beats a long vague list.
Why did Spring Boot 4 split auto-configuration into modules?
To make the codebase smaller and clearer. Each technology now has its own module, root package, starter and test starter, so an application only carries the auto-configuration it uses. It also makes dependencies explicit: Flyway or Liquibase no longer work just because the library is on the classpath; you add their starter.
What is JSpecify and how does Spring use it?
JSpecify is a standard set of nullness annotations (@NullMarked, @Nullable, @NonNull, @NullUnmarked) agreed by several tool vendors. Spring Framework 7 and Spring Boot 4 annotate their own APIs with it, replacing Spring's JSR 305-based annotations. Applications can use it too, usually with @NullMarked on packages and a checker such as NullAway in the build.
How does API versioning work in Spring Boot 4?
You configure where the version comes from (header, query parameter, path segment or media type parameter), for example spring.mvc.apiversion.use.header=API-Version. Controller methods then declare version = "1.0" for a fixed version or version = "1.2+" for a baseline. Spring resolves, parses and validates the version and routes the request to the best matching method.
What happens when a client sends an unsupported API version?
Spring throws InvalidApiVersionException and returns 400 Bad Request. If the version is missing and versioning is required (the default), it throws MissingApiVersionException, also a 400. If a version is supported but no method can serve it, the result is NotAcceptableApiVersionException, again a 400.
How do you deprecate an old API version?
Configure an ApiVersionDeprecationHandler. The built-in StandardApiVersionDeprecationHandler adds Deprecation, Sunset and Link response headers (RFC 9745 and RFC 8594) for the versions you mark, so clients learn about the retirement date from the responses themselves.
What are HTTP service clients, and why use @ImportHttpServices?
An HTTP service client is a Java interface annotated with @GetExchange, @PostExchange and so on, for which Spring generates the implementation. @ImportHttpServices registers those interfaces as beans in named groups, and Spring Boot configures each group from spring.http.serviceclient.<group>.*. You get typed clients without writing a proxy factory per interface.
How is @Retryable in Spring Framework 7 different from Spring Retry?
It lives in Spring Framework itself (org.springframework.resilience.annotation), so no extra dependency, and it is enabled with @EnableResilientMethods instead of @EnableRetry. The attributes are simpler (maxRetries, delay, multiplier, jitter, maxDelay, includes), it supports reactive return types, and it has no @Recover-style fallback method: when retries run out, the last exception is rethrown to the caller. Retry also wraps @Transactional, so each attempt gets a fresh transaction.
What does @ConcurrencyLimit do, and why does it matter with virtual threads?
It caps how many threads can run the annotated method at the same time; extra callers wait. With platform threads, a fixed thread pool often acted as an accidental limit. With virtual threads you can have thousands of concurrent requests, so a fragile downstream system needs an explicit limit. @ConcurrencyLimit(1) effectively serializes access.
What changes for JSON with Jackson 3 in Spring Boot 4?
Packages move from com.fasterxml.jackson to tools.jackson (annotations keep the old package), the mapper becomes an immutable JsonMapper built with a builder, and Boot's customizers and annotations are renamed (JsonMapperBuilderCustomizer, @JacksonComponent). Some defaults change, which spring.jackson.use-jackson2-defaults can soften during migration.
Why was @MockBean removed, and what replaces it?
@MockBean and @SpyBean were Spring Boot features. Spring Framework 6.2 added equivalent, framework-level @MockitoBean and @MockitoSpyBean, so Boot deprecated its own in 3.4 and removed them in 4.0. The replacements work on test class fields; unlike @MockBean, they cannot be declared inside @Configuration classes.
Why did Spring Boot 4 drop Undertow?
Spring Boot 4 requires Servlet 6.1, and Undertow does not support it yet. Rather than ship a server that cannot meet the baseline, Boot removed the Undertow starter and embedded support. Tomcat 11 and Jetty 12.1 remain, plus Reactor Netty for WebFlux.
What is BeanRegistrar, and when would you use it instead of @Bean?
BeanRegistrar is a Spring Framework 7 interface for registering beans in code. Its register(BeanRegistry, Environment) method can register many beans, use loops and conditions, and set scope or lazy initialization. Use it when one @Bean method per bean is not flexible enough, for example when beans depend on configuration lists.
How would you migrate a large Spring Boot 3 application to Spring Boot 4?
In small, testable steps. Upgrade to the latest 3.5.x and clear deprecations; confirm third-party library versions; bump to 4.x with the properties migrator; fix starters (classic starters as a temporary bridge); move to Jackson 3; fix tests; then remove the temporary pieces. In a multi-module build, migrate shared modules first and keep the Java upgrade as a separate change.
What the interviewer is checking: risk management. Mention running integration tests, rolling out to a test environment first, and having a rollback plan. That matters more than remembering every renamed property.
Practise with the full question bank
- Spring Boot Interview Questions: Most Commonly Asked: 500+ curated Spring Boot interview questions by difficulty, with detailed answers, coding challenges and cheat sheets.
- Spring Boot Annotations Mastery: a print-friendly guide to the Spring Boot annotations you actually use, with copyable code and interview questions.
Related reading
- Spring Boot Annotations Cheat Sheet: every annotation you use, explained.
- Spring Boot in Production: A Pre-Deploy Checklist: what to check before your upgraded app goes live.
- Spring Security JWT with Spring Boot: a step-by-step JWT setup on the current Spring Security.
FAQ
Is Spring Boot 4 stable enough for production?
Yes. Spring Boot 4.0 has been generally available since November 2025, and the 4.1 line is on its second maintenance release (4.1.2). With open-source support for 3.5 ended in June 2026, 4.1 is the line to be on for new work and supported upgrades.
Do I need Java 25 for Spring Boot 4?
No. Java 17 is the minimum. Java 25 is recommended because it is the current LTS, but Spring Boot 4 runs on 17 and 21 as well.
Can I skip 4.0 and go straight from Spring Boot 3.5 to 4.1?
You can, but read both the 4.0 migration guide and the 4.1 release notes. Anything deprecated in 4.0 is removed in 4.1, so you get no deprecation warnings as a safety net. Clearing 3.5 deprecations first matters even more.
Is spring-boot-starter-web removed in Spring Boot 4?
Not yet. It is deprecated in favor of spring-boot-starter-webmvc and will be removed in a future release. Switch now so the next upgrade is one less change.
Does Spring Boot 4 still support Jackson 2?
Only as a deprecated stop-gap through the spring-boot-jackson2 module. Plan to move to Jackson 3; Spring Framework currently plans to remove Jackson 2 support in 7.2.
Do I still need Resilience4j with Spring Boot 4?
For circuit breakers, rate limiters and bulkheads with metrics, yes. Spring Framework 7 only adds retry (@Retryable) and concurrency limiting (@ConcurrencyLimit). For a simple retry around one call, the built-in annotation is enough.




