🔁 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