Stateful vs Stateless Design
HTTP/HTTPS and WebSockets both pointed here as the general form of a tension they each hit concretely: whether a server needs to remember anything about a specific client between requests. That single design decision — stateless or stateful — quietly determines how easily a service can be horizontally scaled.
Stateless: every request stands alone​
A stateless service treats every request as complete and self-sufficient — nothing about handling it depends on anything the server remembers from a previous request from that same client. This is why statelessness and Horizontal Scaling go together so naturally: if literally any instance can handle literally any request without needing prior context, a Load Balancer can route requests to any healthy instance with zero coordination, and adding or removing instances never risks losing anything, because no instance is holding anything unique.
Stateful: the server remembers​
A stateful service holds context specific to one client between requests — a login session, a shopping cart, an open WebSocket connection. This pins that client to whichever specific instance is holding its state: the load balancer needs sticky routing to keep sending that client back to the same instance, and if that instance dies, whatever it was holding is gone unless it was also persisted somewhere durable.
Statelessness doesn't mean state disappears — it means it moves​
This is the detail worth being precise about: choosing "stateless" doesn't mean a system has no state to manage at all — a shopping cart is still real data that has to live somewhere. It means that state is externalized to a shared store every instance can reach — a database, or a distributed cache — rather than kept in any one instance's own memory. The server handling a given request looks the state up fresh each time, from the same shared source any other instance would also check, which is exactly what makes any instance interchangeable again.
Why some things resist statelessness anyway​
Not everything can be cheaply externalized. A WebSocket connection is a stateful thing by nature — the open connection itself is the state, and it fundamentally lives on one specific machine's network socket, not in a shared database. This is why WebSockets are the concrete example named as deliberately trading away statelessness: some capabilities (a persistent, low-latency, bidirectional channel) simply require holding state somewhere specific, and the honest move is to accept that cost explicitly — sticky routing, a shared broadcast layer across instances — rather than pretend it can be avoided.
Why this matters in an interview​
Any design question about scaling a service should surface this explicitly: is the workload stateless (trivially horizontally scalable) or does it hold state that needs to be externalized or handled with sticky routing? Naming where client state actually lives — server memory, a shared cache, a database — is a concrete, checkable detail that shows the tradeoff has been thought through, rather than assuming "just add more servers" works unconditionally.
Stateless vs. stateful design: pros and cons​
Stateless
- Any instance can handle any request — trivial to add or remove capacity
- A dead instance loses nothing, since it wasn't holding unique client state
- No sticky routing or session-affinity infrastructure required
Stateful
- Requires sticky routing to keep a client pinned to the instance holding its state
- A dead instance can lose whatever state it was holding, unless persisted elsewhere
- Harder to scale — capacity has to account for where existing state already lives
Further Reading​
- AWS Well-Architected Framework — Stateless applications — practical guidance on externalizing state to enable horizontal scaling.
- Martin Fowler — Bliki: Session State — a concise treatment of where session state can live and the tradeoffs of each option.
Saved locally in your browser — visible in the sidebar as you go.