REST Is Stateless
That doesn't mean your app is
There's this recurring confusion in backend discussions:
"If REST is about Representational State Transfer, how can it be stateless? Aren't we literally transferring state?"
Let's break it down.
Stateless ≠ No State
Stateless means:
The server doesn't store per-client memory in RAM between requests.
Back in the early web days, we used server-side sessions (in-memory) to track users across requests. That made servers stateful and tightly coupled user flows to a specific machine.
That Broke Things
- Couldn't scale horizontally (sticky sessions, ugh)
- Crash a node? Lose user progress
- Caching and retries were unpredictable
So we learned to externalize state—usually into a DB or cache—and make each request self-contained.
So What Does "State Transfer" Mean?
REST doesn't mean "no state"—it means state lives on the client.
- The client sends all context needed to process a request
- The server responds with the current representation of resource state
That's the "transfer" part—the client drives the flow.
Example: Onboarding Wizard
Say you build a 4-step onboarding flow:
POST /onboarding => { flowId: "abc123" }
PUT /onboarding/abc123/step/1 => { personalInfo }
PUT /onboarding/abc123/step/2 => { contractDetails }
✅ The server never remembers your session
✅ It uses flowId to load and persist state
✅ It's stateless, but still supports stateful flows
Why This Matters
Storing session state in server memory locks you in:
- Hard to autoscale
- Hard to recover from failures
- Hard to decouple services
This is why statelessness became a best practice. Not because it's "clean"—but because it's scalable, resilient, and plays well with modern infra.
Gotchas
- Stateless API ≠ no persistence — Your DB is the server's long-term memory
- You can break the rule (e.g. multiplayer, WebSockets) — but that requires strong coordination (e.g. distributed state)
Real-World Pattern
You want to persist where users are in a workflow?
Don't track it in RAM. Persist it:
- In a backing store (Postgres, Redis, etc.)
- Or encoded in a token/URL
Client sends a flowId or token in each request. Server stays stateless—app stays stateful.
The Takeaway
- Stateless server ≠ stateless app
- State transfer = client includes the context in every request
- You get robustness, scaling, and clarity—without giving up complex flows
TL;DR
- Stateless: Server holds no in-memory session
- State transfer: Client manages context, server processes statelessly
- Modern web flows: Use DBs or tokens, pass IDs in every call—and scale without fear