Idempotent Operations
An operation is idempotent if doing it once has the same effect as doing it many times. In distributed systems where retries and duplicates are normal, idempotency is not optional — it's the difference between safe retries and double charges.
How it works
An operation is idempotent if calling it once produces the same result as calling it multiple times. Mathematically: f(f(x)) = f(x).
- Idempotent:
PUT /users/42 {name: 'Ada'}— setting a value. Doing it 1 time or 100 times results in the same state. - Not idempotent:
POST /charges {amount: 100}— creating a resource. Doing it twice creates two charges.
In a perfect world, you call an API once and it works. In the real world, networks fail, timeouts happen, and clients retry. If the operation isn't idempotent, retries cause duplicates.
HTTP methods and idempotency:
- GET: idempotent (and safe — no side effects).
- PUT: idempotent — replaces the resource. PUT /users/42 {name:'Ada'} 10 times = same result.
- DELETE: idempotent — deletes the resource. Deleting a non-existent resource returns 404, but the state is the same.
- POST: NOT idempotent — creates a new resource each time.
- PATCH: NOT necessarily idempotent — depends on the operation (PATCH with 'set name to Ada' is idempotent; PATCH with 'increment count by 1' is not).
To make POST idempotent, use an idempotency key: a unique ID sent by the client that the server uses to deduplicate.
The client generates a unique key (UUID) for each logical operation and sends it in a header: Idempotency-Key: 7c8d2f3a-.... The server stores the key + result. If it sees the same key again, it returns the stored result instead of re-processing. Stripe's API popularized this pattern. It's the standard way to make payments safely retryable.
Your payment API receives a POST /charge request, but the network times out. The client retries with the same Idempotency-Key. What should the server do?
Pick one answer.
Which HTTP method is NOT idempotent by default?
Pick one answer.
Engineering mental model
Mental model. Think of Idempotent Operations as a deliberate boundary in a system. The boundary exists because something becomes harder to manage when everything is done in one place: latency, scale, failure isolation, consistency, cost, or team ownership. The useful question is not “what does Idempotent Operations mean?” but “what pressure makes this boundary worth introducing, and what new failure mode does it create?”
Before choosing Idempotent Operations, name the workload, the critical user path, the dominant bottleneck, the failure you are trying to absorb, and the trade-off you are willing to accept. If you cannot name those five things, the design is probably premature.
// Pseudocode
request = receive()
result = idempotent_operations(request)
return result
// Production questions:
// 1. What happens on timeout?
// 2. Can this operation be retried safely?
// 3. What is the bottleneck?Back-of-the-envelope reasoning
Numerical lens: write down traffic, payload size, read/write ratio, peak multiplier and durability target before choosing a component. The numbers should justify the architecture.
Interactive thought experiment: Idempotent Operations
Change the variables below and predict what breaks first in Idempotent Operations. The production lab can later reuse these same inputs.
Change one variable at a time. Predict the failure mode first, then move the slider and see whether your mental model matches the simplified system response.
If you are stuck on Idempotent Operations, start by drawing the request path and marking every network hop, stateful component, queue, cache and failure boundary. Then estimate where the system will saturate.
You increase traffic by 10× in a system using Idempotent Operations. What should you inspect first?
Pick one answer.
Which statement is the safest engineering habit when using Idempotent Operations?
Pick one answer.
You have dashboards for traffic, latency, errors and saturation. You can change the architecture, but every change has operational cost.
Production scenario: your system uses Idempotent Operations, traffic suddenly spikes, and p99 latency doubles. What is your first move?
Interview drill
Answer this without notes: When would you choose Idempotent Operations, and when would you intentionally avoid it? Mention at least one bottleneck it addresses, one failure mode it introduces, and one alternative. Then quantify the workload you are designing for.
A useful engineering lens for Idempotent Operations: define the problem it solves, the simpler design that fails first, the constraint that forces you to introduce this concept, and the new failure modes the concept creates.
Numerical sanity check
Back-of-the-envelope reasoning beats fake precision. State your traffic, payload, concurrency and growth assumptions explicitly, then calculate enough to know whether the current architecture is orders of magnitude away from the target.
Do not optimize for a memorized definition. Reason from the workload and failure mode.
Imagine the simplest version of a system using Idempotent Operations. What breaks first as traffic grows by 10×, and what would you change before reaching 100×?
Pick one answer.
What you gain, what you pay
- +Safe retries — the foundation of reliable distributed systems.
- +Handles duplicate messages (at-least-once delivery).
- +Prevents double charges, duplicate sends, inconsistent state.
- −Requires a unique key per logical operation — client must generate and track keys.
- −Server must store key→result mapping (storage cost, TTL management).
- −Not all operations are naturally idempotent — some require extra work (optimistic locking, conditional updates).
How this breaks in production
- Idempotency key collision — two different operations get the same key (use UUIDs to prevent).
- Key TTL expires too early — retry after TTL results in duplicate processing.
- Race condition — two requests with the same key arrive simultaneously (use a lock or insert-only table).
Don't fall into these traps
- •Treating POST as idempotent — it's not; use idempotency keys.
- •Forgetting that PATCH is not necessarily idempotent (depends on the operation).
- •Not storing the result — if you only check 'have I seen this key?' but don't return the original result, the client gets a different response on retry.
Real systems using this
How real systems implement this
- Stripe API — Accepts Idempotency-Key header on all POST requests. Stores key→result for 24h. Retries with the same key return the original result.
- AWS SQS — Supports deduplication IDs for FIFO queues. If a message with the same dedup ID is sent within 5 minutes, SQS returns the original instead of creating a duplicate.
Practice saying it out loud
- Q1What is idempotency? Why does it matter in distributed systems?
- Q2How do idempotency keys work? When would you use them?
- Q3Which HTTP methods are idempotent? How do you make POST idempotent?
Further reading & references
Core explanations are original NO CAP material. External references are provided for deeper study and standards.
What next?
Mark as understood once the mental model clicks.
Next recommended
Retry