systemsMarch 21, 20264 min read

Stateless Servers: Why They Scale and Stateful Ones Don't

What it means for an app server to be stateless, why it matters for horizontal scaling, and the one pattern that breaks everything when teams add a load balancer without thinking about state.

Stateless Servers: Why They Scale and Stateful Ones Don't

What Is a Stateless Server?

A stateless server stores no session or user-specific data locally. Every request carries everything the server needs to process it — the server itself is interchangeable.

Request 1 can be handled by Server A. Request 2 from the same user can be handled by Server B. Server B doesn't need to know what Server A did. It doesn't need to ask Server A anything.

Any server, any request. That's statelessness.


The Problem With Stateful Servers

The opposite — a stateful server — stores user session data in local memory. User logs in, session is stored in Server A's RAM. Their next request must also go to Server A because Server B doesn't have that session.

This creates sticky sessions — the load balancer has to pin each user to one server. Now:

  • You can't freely distribute load (some servers get busy users, some get idle ones)
  • If Server A crashes, all its sessions are gone — those users are logged out
  • Deploying Server A means temporarily kicking out all pinned users
  • Horizontal scaling becomes theater — you have more servers but can't use them freely

Common mistake

Building a session-based auth system with in-memory sessions, adding a load balancer, and then wondering why half of users randomly get logged out. The load balancer is sending them to servers that don't have their session.

How Stateless Works in Practice

Move all session state out of the server and into a shared external store — typically Redis.

Instead of storing the session in Server A's RAM, you:

  1. Create the session
  2. Store it in Redis with a session ID
  3. Return the session ID as a cookie
  4. On every subsequent request, any server looks up the session ID in Redis
  5. Gets the session data, processes the request

All servers share the same Redis. Any server can handle any request.

plain
1Before (stateful):
2User → LB → Server A (has session in RAM)
3User → LB → Server B (no session) → 401
4
5After (stateless + Redis):
6User → LB → Server A → Redis (session lookup) → ✓
7User → LB → Server B → Redis (session lookup) → ✓

Rule of thumb

If you plan to run more than one app server, you must externalize all session state before adding a load balancer. This isn't optional.

What "Stateless" Actually Means for Your Code

A stateless server should not rely on:

  • In-memory session stores (express-session defaults to this — dangerous)
  • Local disk writes that need to be read by the same server later
  • Instance-specific configuration that differs between servers

A stateless server can use:

  • JWT tokens — self-contained, no server-side session needed
  • Redis sessions — shared across all instances
  • Database — always accessible from any server
  • Shared object storage (S3, GCS) — for files

When This Matters Most

Statelessness becomes critical the moment you add a load balancer. But it's worth designing for from day one because:

  • Auto-scaling — cloud providers spin up new server instances automatically; they have no existing state
  • Deployments — rolling deploys replace servers; new servers start fresh
  • Crash recovery — when a server crashes, requests need to continue on other servers without data loss

Note

Stateless doesn't mean your system has no state. It means state lives in designated state stores (databases, caches, object storage) — not on individual servers. The servers are computing units, not data stores.

Real World

Every major cloud-native application runs stateless app servers. AWS, GCP, and Azure's auto-scaling groups all assume stateless servers — they add and remove instances based on load, and any instance must be able to serve any request.

Netflix explicitly designed their servers to be "cattle, not pets" — any server can be killed and replaced without affecting users, because no server holds unique state.


Takeaways

  • A stateless server stores no session data locally — any instance can handle any request
  • Stateful servers create sticky sessions, which break horizontal scaling
  • Move session state to Redis (shared across all instances)
  • JWT tokens are another approach — the token carries state, no server storage needed
  • Design for statelessness before adding a load balancer, not after
  • Stateless servers enable auto-scaling, rolling deploys, and crash recovery
Share