skip to content

Statelessness

The constraint that every request carries its own context, from credentials to pagination cursors, instead of leaning on server-side session state. Interviewers ask because it is what makes an API horizontally scalable, and where most 'RESTful' claims quietly break down.

part ofAPI stylesoverview, primer and where to startread it →
on this pageshow

questions

9

A candidate says a REST API cannot be stateless because it stores orders in a database. Explain why that is wrong by distinguishing the two kinds of state involved.

level: juniorimportance: must knowfreq 72%

answer

  1. Resource state = the data; application state = the conversation
  2. Client holds where-am-I; server holds what-is-true
  3. Test: could a cold instance serve this request?
  4. Turn a wizard into a cart resource
  5. A database is not a violation

basics

~20 s

Two different things. Resource state is the durable data the API manages - orders, users - and storing it is the point of the API. Application state is per-client context between requests, like where you are in a flow. Statelessness forbids only the second.

solid answer

~50 s

Statelessness constrains **application state**, not **resource state**. Resource state is the domain data the API exposes and mutates: orders, users, documents. It is shared, durable, addressable by URL, and identical no matter which client asks. Storing it is the purpose of the API; a REST API with no resource state would have nothing to serve. Application state - also called session or conversational state - is where a particular client is in its interaction: who is logged in, which step of a wizard, which page of a result set, what was selected. REST says this is kept by the client and sent with each request, so the server never needs to remember a client between calls. The practical test is: could a different server instance, with no memory of previous calls, handle this request correctly using only the request plus shared storage? If yes, it is stateless, database or not.

go deeper

for a junior

Give the two definitions cleanly with one example each, and state that storing orders is resource state and therefore fine.

for a middle

Add the instance-interchangeability test and the pattern of promoting conversational state into an addressable resource.

for a senior

Tie it to consequences - cacheability, retry safety, free routing - and name the costs, such as larger requests and repeated per-request auth work.

for a principal

Frame it as a state-placement decision across client, shared store and node, and discuss which flows genuinely justify server-held context.

## The two words that get conflated Almost every confusion about REST statelessness comes from using "state" for two different things. **Resource state** is the data the API is about. An order, a user profile, a document, an account balance. It is durable, shared across all clients, addressable by a URL such as `/orders/1234`, and changed by requests (`POST`, `PUT`, `PATCH`, `DELETE`). Two different clients asking for `/orders/1234` should see the same thing. Storing it in a database is not a violation of anything - it is the entire job. **Application state** (equivalently session or conversational state) is where one particular client currently is in its interaction with the service. Examples: which user is authenticated on this connection, which step of a five-step signup has been completed, which page of search results is next, which items are selected in the UI, which filter is applied. This state is *about a client*, not about the domain. The REST constraint is: **application state lives on the client**, and each request carries whatever slice of it the server needs. ## Why the distinction is drawn there Application state is what makes servers non-interchangeable. If instance A remembers that this client is on step three, then this client must keep talking to instance A. Resource state does not have that property, because every instance reaches the same database and sees the same order. So the constraint is really about **interchangeability**, and the test is operational: if this exact request arrived at a freshly started instance that had never seen this client, would it be handled correctly? A `GET /orders/1234` with a valid credential: yes - it reads shared storage. A `POST /checkout/next-step` that relies on the server remembering steps one and two: no. ## Concrete pairs - *Stateful*: the server remembers you are on page 3 and `GET /search/next` returns page 4. *Stateless*: the client sends `GET /search?q=shoes&cursor=eyJ...`, which fully describes the position. - *Stateful*: login creates a server-side session object holding your identity and roles; requests carry only its id. *Stateless*: each request carries a self-contained credential the server can validate on its own. - *Stateful*: a checkout flow accumulates in server memory until the final submit. *Stateless*: each step creates or updates a real, addressable resource - `PATCH /carts/abc` - so progress is resource state anyone can read back. That last pattern is the general trick: **turn conversational state into an addressable resource**. A half-finished checkout stops being an in-memory conversation and becomes a cart with an id and a status. It is now durable, inspectable, resumable from another device, and any instance can continue it. ## What follows from getting this right Self-contained requests are cacheable (a proxy can reason about them from the request alone), retryable (a retry means the same thing), debuggable (a captured request reproduces the behaviour in isolation), and routable to any instance. Requests do get larger and authentication work is repeated per call - that is the acknowledged trade. ## Answering the interviewer Say it in one line - statelessness is about session state, not stored data - then give the two definitions, then the instance-interchangeability test. If you want to go further, mention that the durable-data side is exactly why REST APIs can also be cached and load balanced without special routing.

  • Where should a multi-step signup flow keep its progress in a stateless API?
    Make the in-progress signup a real resource: POST /registrations returns an id, then each step patches that resource. Progress becomes resource state in shared storage rather than conversational state in one instance's memory, so any instance can continue it and the user can resume on another device.
  • Is caching a response on the server a violation of statelessness?
    No. A cache is an optimisation over shared or derivable data, and correctness must not depend on it - a cold instance must still answer correctly, just more slowly. It becomes a violation only if the cache holds per-client state that exists nowhere else, so a different instance would answer incorrectly.

A library is stateless toward you: the shelves hold the books (resource state), but the librarian does not remember which page you were on - you carry your own bookmark (application state).

saying these in an interview costs you the question

  • Saying a stateless API cannot use a database or must be read-only
  • Treating an in-memory HTTP session as acceptable because the session id travels in a cookie
  • Confusing statelessness with idempotency or with immutability
  • Claiming statelessness means the server keeps nothing at all
  • Assuming stateless implies no authentication is possible

context

open as a page

A REST API is described as stateless so that any instance can serve any request. Explain concretely what that means for load balancing and horizontal scaling, and what kinds of server-side data break the property.

level: middleimportance: must knowfreq 70%

basics

~20 s

Each request carries everything needed to process it, so no instance holds per-client memory. The load balancer can send any request to any instance and you scale by adding instances. Per-client data in one instance's local memory breaks it.

open as a page

Compare a self-contained signed token, such as a JWT whose claims the API validates locally, with an opaque token that the API must resolve by calling an introspection or lookup service. What does each cost at request time?

level: middleimportance: must knowfreq 68%

basics

~20 s

A self-contained token carries its claims and a signature, so the API validates it locally with no lookup: fast and dependency-free, but the claims are a snapshot valid until expiry. An opaque token is a random string the API must resolve remotely: always current and instantly revocable, at the cost of a call on every request.

open as a page

What does it mean for an HTTP request to be self-contained, and how would you redesign a paginated endpoint that currently relies on the server remembering which page each client last received?

level: middleimportance: should knowfreq 55%

basics

~20 s

Self-contained means the request carries everything needed to process it: credentials, target, and position. For pagination, put the position in the request - an offset or an opaque cursor the server returns to the client - instead of a server-held cursor.

open as a page

Compare how a stateless HTTP service and one using in-memory server sessions behave during a rolling deployment, a sudden instance crash, and an autoscale scale-in event. What must you still get right in the stateless case?

level: seniorimportance: should knowfreq 48%

basics

~20 s

Stateless: killed instances only lose in-flight requests, so rolling deploys, crashes and scale-in are routine. In-memory sessions: every replaced or crashed instance logs its users out. You still need connection draining, retry-safe requests and readiness checks.

open as a page

Rate-limit counters, an idempotency-key deduplication table, and a response cache are all server-side data that persists between requests. Explain which of these are compatible with a stateless HTTP API and what makes the difference.

level: seniorimportance: should knowfreq 45%

basics

~20 s

All three are fine if they live in shared storage every instance can reach and the request still describes itself. They break statelessness only when kept locally per instance, so correctness depends on which node the request happens to hit.

open as a page

With a self-contained token used as the API credential, what does logout actually accomplish, and how do you design revocation so that disabling an account takes effect quickly without a lookup on every request?

level: seniorimportance: should knowfreq 60%

basics

~20 s

Client-side logout only discards the local copy; a stolen token still works until it expires. Design for it: keep access tokens short-lived, store the refresh credential server-side so it can be deleted, and if you need faster, check a small replicated denylist or a per-user token version.

open as a page

A team proposes moving server-side session data out of instance memory into a shared Redis cluster so the service can scale horizontally. Evaluate that choice against pushing the same context into self-contained requests, and say when you would pick each.

level: principalimportance: nice to knowfreq 35%

basics

~20 s

Redis restores any-instance routing but relocates the state rather than removing it: you gain instant revocation and small requests, and take on a shared dependency, a round trip per request, and a new failure and capacity domain. Self-contained requests remove that dependency but make revocation and payload size harder.

open as a page