May 28, 2026
26 min

Top 50 Spring Boot Interview Questions and Answers (2026)

50 Spring Boot interview questions with straight answers: annotations, starters, JPA, security, testing, Actuator, and microservices patterns for 2026.

By The Interview Coder team

Spring Boot shows up in almost every Java backend interview. The questions are predictable: annotations, auto-configuration, JPA, security, testing, and a few microservices patterns. The problem is that most candidates can use Spring Boot but cannot explain it. That gap is exactly what interviewers probe.

This guide covers 50 Spring Boot interview questions with direct answers, grouped by topic. Read it after you have the Java fundamentals down — if you need a refresher, start with these Java interview questions and the basics of coding interviews. Everything here reflects Spring Boot 3+ behavior: Java 17 minimum, the jakarta.* namespace, and the current Spring Security configuration style.

Spring Boot basics and core annotations

These come first in nearly every screen. Get them tight enough to answer in under a minute each.

1. What is Spring Boot, and how is it different from the Spring Framework?

Spring Boot is an opinionated layer on top of the Spring Framework. Spring gives you the core machinery: dependency injection, MVC, transaction management. Spring Boot removes the setup work around it. It auto-configures beans based on what is on your classpath, ships an embedded server so you run a jar instead of deploying a WAR, bundles dependencies into starters, and adds production tooling through Actuator. With plain Spring you write the configuration. With Spring Boot you override defaults only when you need to.

Why they ask it: It is the standard opener. A vague answer here sets the tone for the rest of the interview.

2. What does @SpringBootApplication do?

It is shorthand for three annotations. @SpringBootConfiguration marks the class as a source of bean definitions. @EnableAutoConfiguration turns on Spring Boot's auto-configuration. @ComponentScan scans the class's package and everything below it for components. That last part matters in practice: if a bean lives outside the main class's package tree, it will not be picked up unless you set scanBasePackages. Knowing the three pieces lets you answer follow-ups like "why isn't my bean found" without guessing.

3. How does auto-configuration work under the hood?

Spring Boot reads a list of candidate configuration classes from META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports (older versions used spring.factories). Each candidate is guarded by conditions: @ConditionalOnClass, @ConditionalOnMissingBean, @ConditionalOnProperty, and similar. Example: if a JDBC driver and connection pool are on the classpath and you have not defined your own DataSource, Boot creates one. Your own beans always win because most auto-configurations back off via @ConditionalOnMissingBean. To debug, start the app with --debug and read the condition evaluation report. To opt out of a specific piece, use @SpringBootApplication(exclude = ...).

Why they ask it: It separates people who use Spring Boot from people who understand it.

4. What is the difference between @Component, @Service, @Repository, and @Controller?

Technically they are all @Component — each registers a bean via component scanning. The differences are semantic plus a few behaviors. @Repository enables exception translation: persistence exceptions get converted into Spring's DataAccessException hierarchy. @Controller (and @RestController) makes the class eligible for request mapping in Spring MVC. @Service adds no extra behavior; it documents that the class holds business logic. Say that plainly. Claiming @Service does something magical is a common way to fail this question.

5. When do you use @Bean instead of @Component?

Use @Component (or its variants) when you own the class and component scanning can find it. Use @Bean inside a @Configuration class when you do not own the class — a third-party client, a RestClient, an ObjectMapper — or when constructing the object needs logic: reading settings, choosing an implementation, wiring constructor arguments manually. @Bean gives you full control over instantiation; @Component is less code when no control is needed. Both end up as beans in the same container.

6. Why is constructor injection preferred over field injection?

Four reasons. Dependencies are explicit: the constructor signature tells you exactly what the class needs. Fields can be final, so the object is immutable after construction. The class is trivially testable — you can new it in a unit test with mocks, no Spring context required. And missing dependencies fail at startup instead of producing a NullPointerException later. Since Spring 4.3, a single constructor needs no @Autowired annotation. Field injection still works, but if you defend it in an interview, expect pushback.

7. What bean scopes does Spring Boot support?

singleton is the default: one instance per application context, shared everywhere. prototype creates a new instance every time the bean is requested. Web apps add request, session, and application scopes. The classic trap question: what happens when you inject a prototype bean into a singleton? The prototype is created once, at injection time, and effectively becomes a singleton. Fixes include ObjectProvider, scoped proxies, or a lookup method. Mention that and the question is done.

8. What do @Primary and @Qualifier do?

Both resolve ambiguity when multiple beans share a type. @Primary marks one bean as the default candidate — injection points with no further hints get that one. @Qualifier("name") is explicit: the injection point names exactly which bean it wants, which overrides @Primary. Rule of thumb: use @Primary when one implementation is the sensible default, and @Qualifier when the caller must choose. If neither is present and two candidates exist, the context fails to start with a NoUniqueBeanDefinitionException.

9. What is the difference between CommandLineRunner and ApplicationRunner?

Both are functional interfaces whose run method executes once the application context is fully started — useful for warmup tasks, seeding data, or one-shot jobs. The only difference is the argument type: CommandLineRunner receives the raw String... args, while ApplicationRunner receives an ApplicationArguments object with parsed option names and values. If you have several runners, order them with @Order. For anything long-running, do not block in a runner; schedule it or run it on a separate executor. A runner that throws an exception prevents the application from starting, which is sometimes exactly what you want for fail-fast checks.

Configuration and starters

Configuration questions test whether you have run an app in more than one environment. The precedence question in particular trips people up.

10. What are Spring Boot starters? Name the ones you use most.

Starters are curated dependency bundles. Instead of hand-picking a dozen compatible libraries, you add one starter and get a tested set with matching versions. spring-boot-starter-web brings Spring MVC, Jackson, and embedded Tomcat. spring-boot-starter-data-jpa brings Hibernate, Spring Data, and a connection pool. Others you should be able to name cold: security, test, actuator, validation, webflux. Version alignment comes from the Spring Boot BOM, so starters carry no version numbers in your build file.

Why they ask it: It is a quick check that you have actually built projects rather than read tutorials.

11. application.properties vs application.yml — does it matter?

Functionally, no. Both feed the same Environment abstraction, and every Boot feature works with either. YAML is easier to read for nested keys and lets you put multiple profile-specific documents in one file separated by --- with spring.config.activate.on-profile. Properties files are flatter and harder to indent incorrectly — YAML whitespace bugs are real. If both files exist, properties entries take precedence over YAML for the same key. Pick one per project and stay consistent.

12. What is the order of precedence for configuration properties?

Simplified, from highest to lowest: command-line arguments, Java system properties, OS environment variables, profile-specific config files (application-prod.yml), then the default application.yml packaged in the jar. Config files located outside the jar override the ones inside it. In tests, @TestPropertySource and the properties attribute of @SpringBootTest sit above all of these. The principle to state: more specific and more external wins, so operators can override anything without rebuilding the artifact.

13. @Value vs @ConfigurationProperties — when do you use which?

@Value("${app.timeout}") injects a single property into a single field. Fine for one-offs. @ConfigurationProperties(prefix = "app") binds a whole tree of properties onto a typed object — nested keys, lists, maps, durations — with relaxed binding (APP_TIMEOUT, app.timeout, and app.time-out all match). It supports JSR-303 validation via @Validated and works cleanly with Java records. For any group of related settings, @ConfigurationProperties is the right answer; sprinkling @Value across twenty classes is a maintenance smell interviewers like to hear you call out.

14. How do Spring profiles work?

Profiles let you swap configuration per environment. Activate them with spring.profiles.active=prod (property, env var, or command line). Profile-specific files like application-prod.yml load on top of the base file and override matching keys. Beans can be conditional with @Profile("prod") or @Profile("!test"). Two things worth adding: spring.profiles.group lets one profile pull in others, and you should keep secrets out of profile files entirely — inject them from the environment or a secret manager instead.

15. Tomcat is the default embedded server. How would you switch to Jetty?

spring-boot-starter-web pulls in spring-boot-starter-tomcat transitively. Exclude it and add spring-boot-starter-jetty instead. That is the whole change — auto-configuration detects what is on the classpath and configures whichever server it finds. Same mechanism for Undertow. For reactive apps, spring-boot-starter-webflux defaults to Netty. Common follow-up: change the port with server.port, or set server.port=0 for a random free port in tests. Other server tuning — thread pools, compression, timeouts — also lives under server.* properties, no server-specific XML required.

REST APIs and data with JPA

This is the longest section because it is where most interview time goes: building endpoints, handling errors, and not shooting yourself in the foot with Hibernate.

16. What is the difference between @Controller and @RestController?

@RestController is @Controller plus @ResponseBody applied to every handler method. With @Controller, return values are interpreted as view names for a template engine unless a method is annotated with @ResponseBody. With @RestController, return values are serialized straight into the response body — JSON by default via Jackson. For an API, use @RestController everywhere. Mixing server-rendered views and JSON in one controller is possible but rarely a good idea.

17. Explain @RequestParam, @PathVariable, and @RequestBody.

@PathVariable pulls a value out of the URL path: /users/{id}. @RequestParam reads query string or form parameters: /users?page=2. @RequestBody deserializes the HTTP request body into an object, typically JSON via Jackson. Path variables identify resources, query parameters filter or paginate them, and the body carries the payload for writes. Bonus points for mentioning that @RequestParam supports required = false and defaultValue, and that a malformed body produces an HttpMessageNotReadableException you should handle.

18. How do you handle exceptions globally in a REST API?

Define a class annotated with @RestControllerAdvice containing @ExceptionHandler methods. Each handler maps an exception type to a response status and body, so controllers stay free of try/catch noise. Since Spring Framework 6 you can return ProblemDetail, a built-in type implementing the problem-details format from RFC 9457 — a standard JSON error shape with type, title, status, and detail. Spring can also emit problem details for built-in errors when you set spring.mvc.problemdetails.enabled=true. Mentioning a consistent error contract, not just the annotations, is what makes this answer senior.

19. How does request validation work?

Add spring-boot-starter-validation (Hibernate Validator). Annotate DTO fields with constraints — @NotNull, @Size, @Email, @Positive — then mark the controller parameter with @Valid. Invalid bodies throw MethodArgumentNotValidException, which becomes a 400 response; you typically catch it in your @RestControllerAdvice to return field-level error messages. For query and path parameters, put constraints directly on the parameters and annotate the controller with @Validated. Custom rules go in a custom ConstraintValidator. Validation belongs at the API edge; do not re-validate the same rules in three layers.

20. What do you get from spring-boot-starter-data-jpa?

Three layers, pre-wired. Hibernate as the JPA implementation. Spring Data JPA, which generates repository implementations from interfaces. And HikariCP as the default connection pool. Auto-configuration creates the DataSource, EntityManagerFactory, and transaction manager from a handful of spring.datasource.* and spring.jpa.* properties. Worth stating in an interview: spring.jpa.hibernate.ddl-auto defaults to create-drop only for embedded databases — for a real database it is none, and schema changes should go through a migration tool, not Hibernate.

21. How do Spring Data repositories work? CrudRepository vs JpaRepository?

You declare an interface; Spring Data generates the implementation at runtime. CrudRepository gives basic CRUD. JpaRepository extends it with JPA extras: batch deletes, flush(), and pagination/sorting support. Query methods are derived from method names — findByEmailAndStatus(String email, Status s) becomes a query automatically. When names get unwieldy, write @Query with JPQL or native SQL. Pagination flows through a Pageable parameter returning Page<T>. If your SQL itself is shaky, these SQL Server interview questions cover the database side.

22. What is the N+1 query problem and how do you fix it?

You load N entities, then a lazy association fires one extra query per entity — N+1 round trips total. It is the most common JPA performance bug. Fixes: a JPQL join fetch, an @EntityGraph on the repository method, or batch fetching via spring.jpa.properties.hibernate.default_batch_fetch_size. Also mention open-session-in-view: Boot enables it by default (spring.jpa.open-in-view=true), which keeps the persistence context open during view rendering and hides lazy-loading errors until production. Most teams turn it off and load what they need explicitly. Detect N+1 by logging SQL in development and reading what actually executes.

Why they ask it: Almost every production JPA codebase has had this bug. They want to know you can spot it.

23. What does @Transactional do, and what are its pitfalls?

It wraps the method in a database transaction via a proxy: begin before the method, commit on success, roll back on failure. The pitfalls are where interviews go. Self-invocation does not work — a method calling another @Transactional method on this bypasses the proxy, so no transaction starts. It only applies cleanly to public methods. By default, rollback happens for unchecked exceptions only; checked exceptions commit unless you set rollbackFor. And a transaction held across a slow external HTTP call pins a connection from the pool — keep transactions short and around database work only.

24. How do you manage database schema changes?

With a migration tool — Flyway or Liquibase — not with ddl-auto=update. Both are auto-configured: put Flyway on the classpath, drop versioned SQL files in db/migration (V1__init.sql, V2__add_index.sql), and migrations run at startup, recorded in a history table so each runs exactly once. Liquibase does the same with XML/YAML/SQL changelogs and adds rollback support. The point to make: schema is versioned code, reviewed and applied identically in every environment. Hibernate generating schema in production is the wrong answer everywhere.

Spring Security

Security questions changed shape with Spring Security 6. Answers built on the old adapter class date you immediately.

25. What happens when you add spring-boot-starter-security?

Every endpoint is locked down immediately. Spring Security auto-configures a filter chain that requires authentication for all requests, generates a default user with a random password printed in the logs, and enables form login plus HTTP Basic. Under the hood it is a chain of servlet filters that run before your controllers — authentication, authorization, CSRF protection, session management each have a filter. Most real apps replace these defaults on day one, but you should be able to describe what the defaults are.

26. WebSecurityConfigurerAdapter is gone. How do you configure security now?

You declare a SecurityFilterChain bean. Spring Security 6 removed WebSecurityConfigurerAdapter; configuration is now component-based with the lambda DSL:

@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/public/**").permitAll()
            .anyRequest().authenticated())
        .oauth2ResourceServer(oauth -> oauth.jwt(Customizer.withDefaults()));
    return http.build();
}

Also note authorizeHttpRequests replaced authorizeRequests, and requestMatchers replaced antMatchers. If a candidate still talks in terms of extending the adapter, it signals they have not touched Spring Security in years.

27. How do you secure a REST API with JWT?

For validating tokens, use the resource server support: add spring-boot-starter-oauth2-resource-server, set spring.security.oauth2.resourceserver.jwt.issuer-uri (or jwk-set-uri) to your identity provider, and enable oauth2ResourceServer(jwt) in the filter chain. Spring fetches the provider's public keys and validates each token's signature, expiry, and issuer — stateless, no session. Claims map to authorities for authorization rules. A JWT (see jwt.io for the format) is signed, not encrypted: never put secrets in claims, keep lifetimes short, and handle revocation via short expiry plus refresh tokens. Issuing tokens yourself is possible but usually a job for an identity provider.

28. What is CSRF protection, and when do you disable it?

CSRF tricks a logged-in browser into sending a forged state-changing request, riding on cookies the browser attaches automatically. Spring Security defends with a synchronizer token: state-changing requests must carry a token the attacker cannot read. The rule for disabling: if your API is stateless and authenticates via a bearer token in the Authorization header, there is nothing for the browser to attach automatically, so CSRF does not apply — disable it. If authentication rides in a session cookie, keep it on. "We disabled CSRF because the tests failed" is the anti-answer here.

29. How does method-level security work?

Annotate the configuration with @EnableMethodSecurity, then guard methods with @PreAuthorize("hasRole('ADMIN')") or expressions referencing arguments: @PreAuthorize("#userId == authentication.name"). @PostAuthorize checks after execution, and @PreFilter/@PostFilter filter collections. It works through proxies, so the same self-invocation caveat as @Transactional applies. Good practice: keep coarse rules (paths, roles) in the filter chain and use method security for fine-grained, domain-level rules — ownership checks, tenant isolation — close to the logic they protect.

30. How do you handle CORS in Spring Boot?

CORS is the browser asking the server whether a cross-origin call is allowed. Three options: @CrossOrigin on a controller for one-offs; a global WebMvcConfigurer with addCorsMappings for app-wide rules; and, when Spring Security is present, configuring a CorsConfigurationSource so the security filter chain handles preflight OPTIONS requests before they get rejected as unauthenticated. That last interaction is the trap: people configure MVC CORS, security blocks the preflight anyway, and they "fix" it by permitting everything. Allow specific origins, not *, when credentials are involved.

Testing

Interviewers use testing questions to gauge how you actually work. Knowing the slice annotations and the context cache is what separates the answers here.

31. What does @SpringBootTest do, and when is it the wrong tool?

@SpringBootTest boots the full application context — every bean, the works — and can start a real server with webEnvironment = RANDOM_PORT. It is right for end-to-end integration tests that exercise the wired application. It is wrong as the default for everything: full-context tests are slow, and a test suite where every class boots the context takes minutes for no reason. Spring caches the context across tests with identical configuration, so every @MockitoBean or @TestPropertySource variation forks a new context. Prefer plain unit tests and slices; reserve @SpringBootTest for genuine integration coverage.

32. What are test slices?

Slice annotations load only the part of the context a test needs. @WebMvcTest(UserController.class) loads the MVC layer — controllers, converters, advice — but no services or repositories; you mock those. @DataJpaTest loads JPA repositories with a test database and rolls back each test. Others: @JsonTest, @RestClientTest, @WebFluxTest. The payoff is speed and focus: a controller test that fails because of a JSON mapping bug, not because some unrelated bean refused to start. Knowing which slice fits which layer is a strong practical signal.

33. How do you replace beans with mocks in a Spring test?

Historically @MockBean: it swaps a bean in the context for a Mockito mock. As of Spring Boot 3.4 it is deprecated in favor of @MockitoBean (and @MockitoSpyBean), which moved into Spring Framework itself — same idea, new home. Two things to say beyond the rename: each distinct set of mocked beans creates a new application context, which slows suites down; and if you can test the class with plain Mockito and constructor injection, no Spring context at all, do that instead.

34. How do you test a controller with MockMvc?

@WebMvcTest plus an injected MockMvc. You perform requests against the MVC machinery without a real server and assert on the result:

mockMvc.perform(get("/users/42"))
    .andExpect(status().isOk())
    .andExpect(jsonPath("$.email").value("a@b.co"));

This exercises request mapping, validation, serialization, and exception handlers — the things unit tests on the controller class miss. Dependencies are mocked with @MockitoBean. For tests against a fully running server, use the RANDOM_PORT web environment with TestRestTemplate or WebTestClient instead.

35. How do you run integration tests against a real database?

Testcontainers. It starts a throwaway PostgreSQL (or anything else) in Docker for the test run, so you test against the real engine instead of H2 — which matters, because H2's SQL dialect differs enough to hide bugs. Since Spring Boot 3.1, @ServiceConnection on the container field wires the connection automatically; no manual @DynamicPropertySource for the URL and credentials. Combine with @DataJpaTest (plus disabling the test-database replacement) or @SpringBootTest. Migrations run against the container at startup, so your Flyway scripts get tested for free.

36. How do you override configuration for tests?

Several layers, from broad to narrow. src/test/resources/application-test.yml plus @ActiveProfiles("test") for a whole test profile. The properties attribute of @SpringBootTest or @TestPropertySource for per-class overrides. @DynamicPropertySource for values only known at runtime, like a container's mapped port. The thing to volunteer: every distinct property combination is a distinct context cache key, so scattering ad-hoc overrides across the suite multiplies context startups. Standardize on a small number of test configurations.

Actuator and observability

These questions show up in any role that owns services in production, which today is most backend roles.

37. What is Spring Boot Actuator?

Production endpoints you get for free. Add spring-boot-starter-actuator and the app exposes operational data over HTTP under /actuator: health status, metrics, environment, loggers, thread dumps, scheduled tasks. Operations teams and orchestrators consume these instead of custom-built status pages. Two follow-ups worth pre-empting: endpoints can be moved to a separate management port (management.server.port), and anything beyond health should sit behind authentication because /actuator/env and /actuator/heapdump leak secrets. Monitoring and deployment pipelines lean on these endpoints heavily — the same territory as these DevOps interview questions.

38. Which Actuator endpoints are exposed by default, and how do you expose more?

Over HTTP, only /actuator/health is exposed by default. Everything else — metrics, env, loggers, threaddump, heapdump — exists but is not web-accessible until you opt in with management.endpoints.web.exposure.include=health,metrics,prometheus (or * in development only). There is a difference between an endpoint being enabled and being exposed; interviewers like that distinction. The blunt rule: expose the minimum, secure the rest, and never ship include=* to production with no auth in front of it.

39. How do health checks work, and how do they integrate with Kubernetes?

/actuator/health aggregates HealthIndicator beans — database, disk space, message broker — into one UP/DOWN status. You add custom checks by implementing HealthIndicator. When the app detects it is running on Kubernetes, Boot exposes liveness and readiness probe groups at /actuator/health/liveness and /actuator/health/readiness. The distinction matters: liveness means "restart me if this fails," readiness means "stop sending me traffic." Putting a database check in liveness is a classic mistake — a database outage would make Kubernetes restart perfectly healthy pods in a loop.

40. How does Spring Boot handle metrics?

Through Micrometer, a vendor-neutral metrics facade — think SLF4J, but for metrics. Boot auto-configures a MeterRegistry and instruments HTTP requests, JVM memory, garbage collection, and data source usage out of the box. You add business metrics with counters, gauges, and timers, plus tags for dimensions. Add a registry dependency like micrometer-registry-prometheus and /actuator/prometheus serves a scrape endpoint; other backends (Datadog, OTLP, CloudWatch) are a dependency swap, not a code change. That decoupling is the design point worth articulating.

41. How do you do distributed tracing in Spring Boot 3?

Micrometer Tracing — the replacement for Spring Cloud Sleuth, which does not work with Boot 3. It propagates trace and span IDs across service calls so one user request can be followed through every hop. You pick a bridge (OpenTelemetry or Brave) and an exporter to send spans to a backend like Zipkin or an OTel collector. Trace IDs land in your logs automatically, which turns "grep five services and pray" into "filter by trace ID." Set management.tracing.sampling.probability deliberately — tracing every request in a high-traffic system is expensive.

Microservices patterns

Less about Spring Boot itself, more about whether you can reason about distributed systems built with it.

42. Why is Spring Boot a common choice for microservices?

Because each service is a self-contained jar with an embedded server: build, containerize, run. No shared application server, no deployment coupling between services. Auto-configuration keeps per-service boilerplate near zero, Actuator gives every service uniform health and metrics endpoints, and the Spring Cloud ecosystem covers the distributed-systems plumbing. Be honest about the flip side if asked: JVM memory footprint and startup time are real costs at high service counts, which is exactly the niche native images target. Microservice design questions quickly become architecture questions — covered in system design interview preparation.

43. What does Spring Cloud add on top of Spring Boot?

The distributed-systems toolkit. Centralized configuration (Spring Cloud Config, or config maps when on Kubernetes). Service discovery (Eureka, Consul, or platform-native discovery). An API gateway (Spring Cloud Gateway) for routing, rate limiting, and auth at the edge. Circuit breakers via the Spring Cloud Circuit Breaker abstraction. Messaging abstractions with Spring Cloud Stream. The nuance interviewers reward: on Kubernetes, a chunk of this is redundant — the platform already does discovery, config, and load balancing — so teams there run a thinner Spring Cloud footprint. Know the overlap; these Kubernetes interview questions cover the platform side.

44. How do you implement a circuit breaker?

With Resilience4j — Hystrix has been in maintenance mode for years and is the dated answer. Annotate a call with @CircuitBreaker(name = "inventory", fallbackMethod = "fallback") or use the functional API. The breaker tracks the failure rate over a sliding window; past a threshold it opens and calls fail fast instead of stacking up threads on a dead dependency. After a wait, it goes half-open and lets trial calls through. Combine with time limiters, retries (with backoff and only on idempotent operations), and bulkheads. The goal is containment: one failing dependency must not take the whole service down with it.

45. How do Spring Boot services communicate with each other?

Synchronous HTTP: RestClient is the current blocking client (Spring Framework 6.1+); WebClient is the reactive one; RestTemplate is in maintenance mode — fine in old code, wrong default for new code. Declarative HTTP interfaces with @HttpExchange let you define a Java interface and have Spring generate the client. Asynchronous: messaging through Kafka, RabbitMQ, or Spring Cloud Stream, which decouples availability — the consumer can be down while messages queue. The judgment call interviewers want: synchronous calls for queries that need an immediate answer, events for state propagation, and never a chain of six synchronous hops to serve one request.

46. How do you handle data consistency across services without distributed transactions?

You give up on two-phase commit — it does not fit independent services — and use patterns instead. Saga: a sequence of local transactions, each publishing an event that triggers the next, with compensating actions to undo previous steps on failure. Orchestrated sagas use a coordinator; choreographed ones react to each other's events. The outbox pattern fixes the "wrote to the database but the event never sent" gap: write the event into an outbox table in the same local transaction, and a relay publishes it afterwards. Accept eventual consistency and design for idempotent consumers, because messages will be delivered twice.

Advanced and performance

Senior-level territory. You will not get all of these in one interview, but one or two of them decide the level you get hired at.

47. A Spring Boot app starts slowly. What do you look at?

Measure first: ApplicationStartup with flight recorder or the startup actuator endpoint shows where time goes. Common causes and fixes: too many beans created eagerly — spring.main.lazy-initialization=true defers creation to first use (with the trade-off that misconfiguration errors surface late); classpath scanning over huge packages; eager database migrations and cache warmups that could run after startup. Beyond that, AOT processing and CDS (class data sharing) cut JVM startup measurably in recent Boot versions, and native images change the game entirely. Saying "measure before tuning" out loud is part of the correct answer.

48. What are GraalVM native images, and what are the trade-offs?

Spring Boot 3 supports compiling your app ahead-of-time into a native executable with GraalVM. Result: startup in tens of milliseconds instead of seconds, and a fraction of the memory — excellent for serverless, scale-to-zero, and dense container fleets. The costs: long compile times; a closed-world assumption, meaning runtime reflection and dynamic proxies must be declared via hints because the compiler removes what it cannot prove reachable; some libraries still lack native support; and peak throughput can trail a warmed-up JVM JIT. The honest summary: native images optimize startup and footprint, the JVM still often wins on long-running peak performance.

49. How do virtual threads change Spring Boot applications?

Set spring.threads.virtual.enabled=true on Java 21+ and Boot runs request handling on virtual threads. Blocking I/O — database calls, HTTP calls — no longer pins an OS thread, so a service can hold thousands of concurrent blocking requests cheaply. The practical consequence: plain blocking Spring MVC code now scales in scenarios that previously pushed teams toward WebFlux, without the reactive complexity. Caveats to mention: pinning still happens inside some synchronized blocks (improved in newer JDKs), connection pools remain a bottleneck regardless of thread count, and CPU-bound work gains nothing.

50. How do you build efficient Docker images for Spring Boot?

Two answers. Buildpacks: mvn spring-boot:build-image produces an OCI image with no Dockerfile, sensible JVM defaults included. Or a Dockerfile that exploits layered jars: Boot's jar separates dependencies, spring-boot-loader, snapshot dependencies, and your application classes into layers, extracted via the jar's tools mode. Dependencies change rarely; your code changes constantly — layering means a rebuild pushes kilobytes, not the full dependency tree. Round it out with a slim JRE base image, a non-root user, and container-aware memory settings. "We copy the fat jar into one layer" is the answer that invites follow-up questions you do not want.

How to use this list

Do not memorize 50 answers word for word. Group them: dependency injection and auto-configuration, data access, security, testing, operations. For each group, build one small project feature that exercises it — a secured endpoint with validation, a repository with a deliberate N+1 you then fix, a Testcontainers test. Interviewers push one level past the first answer, and that second level only comes from having done it.

Interview Coder is a desktop app that helps during live technical interviews — it reads the question on your screen and drafts working answers in real time, with coding answers powered by Claude Sonnet 4.6, Anthropic's latest Sonnet model. There is a free tier to try it; Pro runs $299/month or $799 one-time for lifetime access.

Related Blogs

Explore Our Similar Blogs

View All blogs
Take the Next Step

Ready to Pass Any SWE Interviews with 100% Undetectable AI?

Step into your next interview with AI support designed to stay completely undetectable.