What is the difference between a stateless and stateful service?
A stateless service instance can process each request without its own prior request history, while a stateful service owns information that later requests need for correctness. Stateless tiers scale and recover more easily; stateful tiers require explicit handling of partition ownership, replication, checkpointing, or recovery.
How to think about it
The short answer is: a stateless service instance can handle a request using the request itself plus shared dependencies; it does not need its own memory of earlier requests. A stateful service keeps or owns information that later requests need, so failover means recovering or transferring that information, not merely sending traffic to another replica.
Why the distinction matters
A service instance is one running copy of an application. A replica is another copy of that same application. If every replica can handle every request, a load balancer, which is a component that routes requests, can send traffic wherever capacity is available.
“State” means information that changes over time and affects what the service should do next. A shopping cart, a login session, a database row, a stream-processing window, and a workflow cursor are all examples.
The important boundary is ownership.
A stateless API may read a cart from a database. The cart is still state, but it is not trapped inside the API process. If API replica A disappears, replica B can read the same cart and continue. The API instances are stateless; the database is stateful.
A stateful component owns information needed for correctness. A stream processor that remembers which orders have been paid, or a database that owns account balances, cannot simply be replaced with an empty process. The replacement must restore state, replay a log, receive a replica, or take over a partition.
| Question | Stateless instance | Stateful instance |
|---|---|---|
| Must the next request reach the same copy? | No | Often, unless state is replicated or transferred |
| Typical scaling method | Add interchangeable replicas | Partition, replicate, and rebalance owned state |
| What happens after process loss? | Start a replacement and route traffic to it | Restore, replay, or promote a replica |
| Main cost | Network calls to shared dependencies | Coordination, storage, recovery, and movement of state |
That is usually what the interviewer is probing. They do not just want “stateless scales better.” They want to know whether you understand why: interchangeable instances make routing and replacement simple.
A checkout example
Imagine an online shop with 100,000 active carts. Each cart averages 4 KB, so the cart payload is roughly 400 MB in total.
The API has ten replicas and handles 2,000 requests per second. A user adds a pair of headphones, then immediately opens the cart:
Request 1: POST /cart -> api-3 -> shared cart store
Request 2: GET /cart -> api-7 -> shared cart store
The second request succeeds even though it reached api-7, because the cart is stored in a shared system keyed by the user or session ID. That store might be a suitably configured Redis deployment or a relational database.
The API process itself does not need to remember request 1. If api-3 crashes, the user does not lose the cart. The load balancer can route the next request to any healthy replica.
Now compare that with this design:
cart_by_user[user_id] = ["headphones"]
If cart_by_user lives only in api-3 memory, the design is stateful from the deployment point of view. A request sent to api-7 may see an empty cart. When api-3 restarts, its carts vanish entirely.
The service might appear healthy: CPU is normal, requests return HTTP 200, and error rates stay near zero. Users report that carts randomly empty after a deployment or scale-out. That symptom is often the first clue that supposedly stateless application code has hidden local state.
The same checkout system may also contain a genuinely stateful stream processor. It consumes events such as:
order-1842: payment_authorized
order-1842: inventory_reserved
order-1842: shipment_requested
The processor keeps per-order workflow state so it knows what event is valid next. Suppose 500,000 open orders each require 1 KB of state. That is about 500 MB that must be preserved somewhere. If the work is divided into 50 partitions, each partition is a slice of order keys assigned to a worker.
When one worker fails, another worker must take ownership of its partitions. It restores a checkpoint, which is a saved recovery position and state snapshot, then replays newer events from a durable log. That is stateful recovery. Starting an empty worker and sending it traffic would risk approving an order twice, shipping an unpaid order, or forgetting a timeout.
The production trade-off
Statelessness is not free. A stateless API usually pays for its simplicity with calls to shared stores. Those calls add network latency, create another availability dependency, and can turn the store into a bottleneck. If the API is fast but the session database is overloaded, the user still experiences a slow checkout.
Stateful processing pays a different bill. Keeping local state can avoid repeatedly fetching large data and can make operations such as rolling counts or joins efficient. The price is operational complexity: the system needs ownership rules, partitioning, replication, consistency decisions, and a recovery plan.
Stateful services can absolutely scale. A database can shard data across machines. A stream processor can divide keys into partitions. A distributed cache can spread entries across nodes. But adding a node may require moving state, and moving state takes time and bandwidth. The design must also decide what happens when two nodes believe they own the same partition.
Most real systems are hybrid:
- The HTTP or gRPC request layer is stateless.
- The database is the source of truth.
- A cache holds data that can be recomputed.
- A queue or log preserves events.
- A workflow or stream processor owns intermediate state.
The classification depends on the boundary you are discussing. Saying “the checkout service is stateless” is incomplete unless you clarify whether you mean its API processes or the entire checkout subsystem.
A cache deserves a precise distinction. It contains state, but usually not correctness state, meaning data whose loss would make the system produce an invalid result. If losing the cache merely causes a slower database read, the cache can be disposable. If the cache is the only place holding an uncommitted payment decision, it is no longer safely disposable.
A self-contained signed token can also keep a service stateless. For example, a token may carry a user ID, roles, and an expiry time, allowing any replica to validate it without a session lookup. But that shifts the trade-off. Revoking a token early becomes harder, claims can become stale, and large tokens increase request size. A cookie containing only a session ID does not provide the same property; the server still needs a shared session store.
Sticky sessions, which try to send a user back to the same replica, are another common misconception. They can hide local state during normal operation, but they do not remove it. If that replica dies, the session is still lost unless the state was replicated elsewhere. Sticky routing is a workaround, not a substitute for a recovery design.
There is also a business-state trap. A stateless payment endpoint can still create durable state. If a client retries POST /pay after a timeout, two interchangeable API replicas might both receive the request. The endpoint needs an idempotency key, which is a client-supplied identifier used to recognize repeated attempts, and a durable record of the result. Otherwise “stateless” request handling can produce two charges.
What they will ask next
Is a database-backed application stateless or stateful?
It depends on the boundary. The API instances may be stateless because any instance can load the needed row. The application as a whole still depends on a stateful database. In an interview, I would name both layers instead of forcing the entire system into one label.
Can a stateful service be highly available?
Yes. It can replicate state, checkpoint it, write an append-only log, or use partition ownership with failover. The real questions are how much data must be recovered, whether writes can be lost, how long recovery may take, and how the system prevents two owners from processing the same work.
How would you scale a stateful stream processor?
Partition the stream by a stable key such as order_id, preserve ordering within each partition, checkpoint both processing progress and state, and rebalance partitions when workers change. I would also define duplicate-processing behavior, because a crash between “write the result” and “advance the checkpoint” can cause replay.
Say this in the interview
“A stateless instance needs no local history, so replicas are interchangeable and recovery is mostly replacement; a stateful component owns correctness-critical data, so scaling and failover require partitioning, replication, checkpointing, or replay.”