Concept · Scaling

Stateless Services

01

Why this matters

You want to scale horizontally. Your load balancer spreads traffic across N servers. User Alice's session is in memory on server 3. The LB routes Alice's next request to server 7. Server 7 doesn't know Alice — login lost, cart empty, request fails.

This is what "stateful" means: the server holds session-specific data that determines its behavior. Statelessness is the fix — any server can serve any request. It's the property that makes auto-scaling, blue-green deploys, and load balancing Just Work.

02

The definition

A service is stateless if every request contains all the information needed to handle it, or can fetch that information from an external store. No two subsequent requests from the same user need to land on the same instance.

The classic test: kill any instance right now — does anything permanent break? If users lose data, their cart vanishes, or sessions drop, the service is stateful. If requests just retry on another instance, it's stateless.

03

Where state goes

"Stateless" doesn't mean "no state anywhere" — it means the app server doesn't own it. State lives in:

  • The request itself. JWT in the Authorization header carries user identity. No session lookup needed. Trade-off: JWTs can't be revoked easily before expiry.
  • Redis/Memcached. Session tokens → user_id, preferences, cart contents. Any app server reads the same Redis.
  • The database. Persistent state (orders, posts, profile). What it's for anyway.
  • Object storage (S3). Uploaded files, user-generated media. Never the local disk of an app server.
  • The client. UI state, form input, unsaved drafts. Browser localStorage or the SPA's in-memory state.
04

The stateless checklist

Anti-patternFix
In-memory sessionsMove to Redis or signed cookies / JWT
Local file uploadsUpload directly to S3/GCS
Process-local cacheEither accept soft cache (OK) or move to shared Redis (better for consistency)
WebSocket connections held per-serverAdd a pub/sub layer so any server can deliver to any connection
Scheduled jobs running in-processMove to a cron system with distributed locking
Rate limit counters in memoryRedis INCR with TTL
Feature flags loaded at startupQuery a central flag service or subscribe to change events
05

What stateless gives up

  • Per-request latency. Fetching from Redis adds 1–5ms per call vs in-process access. Usually negligible.
  • External dependency. Your app now depends on Redis being up. Mitigate with connection pooling + circuit breakers.
  • Complexity. Two stores to think about (DB + cache + possibly more).

The trade is overwhelmingly worth it. Every horizontal-scale architecture assumes stateless application tiers. Every container orchestrator (Kubernetes, ECS) assumes pods are disposable.

The mandate

Treat every app server as cattle, not pets. Any instance should be killable without warning; a new one spins up and works identically. If that's not true, find the state and move it.

06

Deep dive — sticky sessions vs true statelessness

Sticky sessions (session affinity) is the middle ground: the load balancer remembers "user Alice → server 3" via a cookie and routes her there for the session's duration. Server 3 keeps her session in memory. Fast, no Redis needed, but:

  • Server 3 dies → Alice's session dies. She's logged out mid-session.
  • Uneven load — long-session users pile onto one server.
  • Scale down is dangerous — killing a healthy instance kills live sessions.
  • Cross-service concerns — if Alice calls service B in the middle, does B also need to stick to her?

Sticky sessions are a pragmatic retrofit when moving to Redis is too expensive. But new systems should skip them. JWT-signed tokens + Redis session storage is the right default in 2025 — any server, any region, any replica can serve any request.

The exception: WebSockets. A WebSocket is inherently stateful — it's a persistent TCP connection to one server. For chat/real-time apps, you accept sticky connections + a pub/sub layer (Redis Streams, NATS, Kafka) to fan out messages across servers.

07

Used in problems

Every problem's API tier in this portfolio is stateless. WhatsApp's session tier is stateful (persistent WebSockets) but the business logic tier above it is stateless — any server can handle any user's request given the connection.

Next up