skip to content

For a Spring WebFlux (reactive) application, which embedded server runs by default and why is it different from the servlet stack?

level: seniorimportance: should knowfreq 50%

answer

  1. WebFlux -> Reactor Netty default
  2. no Servlet API; Reactor Mono/Flux
  3. NettyReactiveWebServerFactory / ReactiveWebServerFactoryAutoConfiguration
  4. event loop vs thread-per-request
  5. can still run WebFlux on Tomcat/Jetty/Undertow

basics

~20 s

Reactor Netty. WebFlux is a non-blocking, reactive stack that doesn't use the Servlet API, so it can't run on a servlet container's thread-per-request model. Netty's event-loop model fits reactive back-pressure; spring-boot-starter-webflux includes it by default.

solid answer

~40 s

WebFlux defaults to Reactor Netty (an event-loop, non-blocking server), not Tomcat. WebFlux is built on Project Reactor and does NOT use the blocking Servlet API — it uses Spring's own reactive HTTP abstraction (HttpHandler / WebHandler) via ReactiveWebServerFactoryAutoConfiguration, which builds a NettyReactiveWebServerFactory. Netty's small pool of event-loop threads handling many connections matches reactive back-pressure far better than Tomcat's thread-per-request model. You can still run WebFlux on Tomcat, Jetty, or Undertow — Spring Boot supports them as reactive servers via the Servlet 3.1+ non-blocking I/O bridge — by excluding Netty and adding the corresponding starter. But Netty is the natural, default choice because it's non-blocking end to end.

code

xml · 23 lines
xml
<!-- Reactive app: Netty by default -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

<!-- To run WebFlux on Tomcat instead of Netty: -->
<!--
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-webflux</artifactId>
  <exclusions>
    <exclusion>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-reactor-netty</artifactId>
    </exclusion>
  </exclusions>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
-->

go deeper

for a junior

Know reactive apps default to Netty, not Tomcat.

for a middle

Explain WebFlux is non-blocking and doesn't use the Servlet API, hence Netty.

for a senior

Contrast event-loop vs thread-per-request, name NettyReactiveWebServerFactory, and note WebFlux can run on servlet containers.

for a principal

Discuss mixed-stack precedence, when reactive is worth it, and running reactive on Tomcat/Undertow for ops reasons.

**Two web stacks in Spring:** - **Servlet stack** = Spring MVC, blocking, thread-per-request, built on the Jakarta Servlet API. Runs on servlet containers: Tomcat (default), Jetty, Undertow. - **Reactive stack** = Spring WebFlux, non-blocking, built on **Project Reactor** (`Mono`/`Flux`) and Spring's reactive HTTP abstractions (`HttpHandler`, `WebHandler`), *not* the Servlet API. **Default server for WebFlux = Reactor Netty.** `spring-boot-starter-webflux` transitively includes `spring-boot-starter-reactor-netty`. At startup, `ReactiveWebServerFactoryAutoConfiguration` detects Netty on the classpath (`@ConditionalOnClass`) and builds a `NettyReactiveWebServerFactory`, which starts an embedded Reactor Netty server (default port 8080). **Why Netty and not Tomcat by default:** Netty uses an **event-loop** model — a small, fixed number of I/O threads (roughly one per CPU core) multiplexing thousands of connections via non-blocking sockets and callbacks. This aligns with reactive **back-pressure** (consumer signals how much it can handle) and lets a WebFlux app sustain high concurrency with few threads and low memory. Tomcat's classic model dedicates a thread per in-flight request, which blocks and doesn't naturally express back-pressure. **You are NOT locked to Netty.** WebFlux can run on Tomcat, Jetty, or Undertow because those containers support non-blocking I/O (Servlet 3.1+ async / `ReadListener`/`WriteListener`). Spring Boot bridges WebFlux onto them via factories like `TomcatReactiveWebServerFactory`. To do so: exclude `spring-boot-starter-reactor-netty` and add the Tomcat/Jetty/Undertow starter. This is sometimes done to reuse existing ops tooling or run reactive + servlet workloads on one container family — but Netty remains the recommended default. **Mixed-stack gotcha:** if BOTH `spring-boot-starter-web` (servlet) and `spring-boot-starter-webflux` are present, Spring Boot defaults the app to the **servlet** stack (`WebApplicationType.SERVLET`) — i.e. it becomes a Spring MVC app with Tomcat, and WebFlux is available only as a library (e.g. for `WebClient`). To force reactive, set `spring.main.web-application-type=reactive`. **Terms:** *Event loop* = thread that loops over ready I/O events and dispatches handlers without blocking. *Back-pressure* = flow-control signal from a slow consumer to a fast producer. *HttpHandler* = the lowest-level reactive contract Spring adapts to each server.

  • Can WebFlux run on Tomcat, and how?
    Yes. Tomcat (Jetty/Undertow too) supports non-blocking I/O via Servlet 3.1+. Exclude spring-boot-starter-reactor-netty and add the Tomcat starter; Boot builds a TomcatReactiveWebServerFactory. Netty is just the default, not a requirement.
  • If both spring-boot-starter-web and spring-boot-starter-webflux are on the classpath, what runs?
    Spring Boot defaults to the servlet stack (WebApplicationType.SERVLET) — a Spring MVC app on Tomcat. Force reactive with spring.main.web-application-type=reactive.

saying these in an interview costs you the question

  • Saying WebFlux runs on Tomcat by default
  • Claiming WebFlux uses the Servlet API
  • Believing WebFlux can ONLY run on Netty
  • Thinking adding both web and webflux starters yields a reactive app

context