skip to content

As an architect, how would you decide among Tomcat, Jetty, Undertow, and Netty for a Spring Boot service?

level: principalimportance: nice to knowfreq 28%

answer

  1. model first: MVC->servlet container, WebFlux->Netty
  2. Tomcat default/mature; Undertow lean; Jetty WebSockets
  3. benchmark YOUR workload, not blog numbers
  4. reactive = whole-codebase commitment
  5. weigh footprint, CVEs, ops familiarity

basics

~20 s

First decide the programming model: blocking MVC -> a servlet container (Tomcat/Jetty/Undertow); non-blocking WebFlux -> Netty. Among servlet containers, keep Tomcat unless you have a measured reason (footprint, throughput, WebSockets, ops standardization) to pick Undertow or Jetty.

solid answer

~40 s

The primary axis is the programming model, driven by WebApplicationType. Blocking Spring MVC needs a servlet container — Tomcat (default, most mature), Jetty (light, strong for WebSockets/long-lived connections), or Undertow (JBoss, low footprint, good throughput). Non-blocking WebFlux fits Netty's event-loop model best, so Netty is the default there. Beyond that, keep the default unless you have evidence: benchmark under your real workload rather than trusting synthetic numbers, since results are workload-dependent and versions move. Secondary factors: memory footprint (Undertow/Netty tend lower), thread-model fit, HTTP/2 and WebSocket needs, security-patch cadence and CVE history, operational familiarity and existing tooling, and container-specific config surface. Don't adopt reactive/Netty just for throughput — it forces a non-blocking codebase end-to-end. Choose the simplest option that meets SLAs.

go deeper

for a junior

Know Tomcat is the safe default and the others are alternatives.

for a middle

Separate the model choice (MVC vs WebFlux) from the container choice among servlet servers.

for a senior

List concrete factors (footprint, connection model, HTTP/2, CVEs) and note WebFlux commits the whole codebase.

for a principal

Give a full decision framework, insist on workload-specific benchmarking, and weigh ops/security/cost alongside performance.

This is an architecture judgment question; interviewers want a **decision framework**, not a claim that server X is fastest. **Step 1 — Programming model first (the dominant decision).** This maps to `WebApplicationType`: - **Blocking / Spring MVC (SERVLET):** thread-per-request, simple mental model, huge ecosystem (blocking JDBC, servlet filters). Runs on a **servlet container**: Tomcat, Jetty, or Undertow. - **Non-blocking / Spring WebFlux (REACTIVE):** event-loop, high concurrency with few threads, requires non-blocking all the way down (R2DBC, reactive clients) or you lose the benefit. Default server is **Netty**. Getting this axis right matters far more than picking between servlet containers — reactive is a whole-codebase commitment, not a server toggle. **Step 2 — Within the servlet stack, choose the container:** - **Tomcat (default):** most battle-tested, best documented, widest operational familiarity, active security response. The safe choice; keep it unless proven otherwise. - **Undertow (JBoss/WildFly):** lightweight, non-blocking core (XNIO), often the smallest memory footprint and strong throughput; fewer people know its tuning knobs (`server.undertow.threads.io/worker`, buffer settings). - **Jetty:** long history of embeddability, popular for WebSocket-heavy and long-lived-connection workloads, flexible. **Step 3 — Netty** is really a *reactive* choice; you pick it by choosing WebFlux, not by swapping a servlet container. (WebFlux *can* run on Tomcat/Jetty/Undertow via Servlet 3.1+ non-blocking I/O, but Netty is the natural default.) **Decision factors to weigh (and verbalize):** 1. **Throughput/latency** — workload-dependent; **benchmark with your real traffic** (payload sizes, keep-alive, TLS, DB latency). Synthetic "X req/s" numbers age fast and mislead. 2. **Memory footprint** — Undertow and Netty typically lean; relevant for dense/containerized/serverless deploys where RAM = cost. 3. **Concurrency model fit** — many slow/long-lived connections (SSE, WebSocket, streaming) favor non-blocking (Undertow/Netty/Jetty); classic request/response with blocking DB is perfectly fine on Tomcat. 4. **Protocol needs** — HTTP/2, WebSocket, TLS/ALPN specifics differ per container. 5. **Security & maintenance** — CVE history and patch cadence; who ships fixes fast; your ability to upgrade. 6. **Operational familiarity** — the team's existing dashboards, access-log formats, tuning experience; a "faster" server nobody can operate is a liability. 7. **Config surface** — properties are container-scoped (`server.tomcat.*`, `server.jetty.*`, `server.undertow.*`); switching means re-tuning. **Anti-patterns to call out:** - Adopting WebFlux/Netty purely for benchmark throughput, then blocking on JDBC inside reactive types — worst of both worlds. - Swapping the default container based on a blog benchmark rather than measuring your own workload. - Ignoring the ops cost of a less-familiar server. **Bottom line to state:** default to Tomcat + MVC for typical services; move to reactive/Netty only when you genuinely need massive concurrency with non-blocking I/O end to end; pick Undertow/Jetty over Tomcat only for a specific, measured reason (footprint, connection model, standardization). Choose the simplest thing that meets your SLAs.

  • A team wants to switch to WebFlux/Netty purely because a benchmark shows higher throughput. What do you advise?
    Caution. Reactive only pays off if the whole path is non-blocking (reactive DB/clients); blocking JDBC inside Mono/Flux negates it and adds complexity. Validate with a load test on real workload, and weigh the codebase and debugging cost, not just synthetic numbers.
  • When would Undertow be a better pick than Tomcat?
    When memory footprint matters (dense/containerized deploys where RAM drives cost) or for workloads with many long-lived/non-blocking connections, provided the team can operate and tune it. Otherwise Tomcat's maturity and familiarity usually win.

saying these in an interview costs you the question

  • Claiming one server is universally 'the fastest'
  • Choosing Netty/WebFlux for throughput while keeping blocking JDBC
  • Deciding on a blog benchmark instead of measuring your own workload
  • Ignoring operational familiarity and security-patch cadence
  • Treating Netty as just another servlet-container swap

context