Idempotency
Designing an operation so that doing it more than once has the exact same effect as doing it once.
What is it?
Networks are unreliable — a request might time out even though the server actually processed it successfully, leaving the client unsure whether to retry. If retrying could cause the operation to happen twice (charging a customer twice, sending a duplicate email), that's a real problem. An operation is called idempotent if performing it multiple times has the exact same effect as performing it once — making it safe to retry without fear of duplicating the result.
Explain like I'm 10
Pressing an elevator call button is idempotent — pressing it five times doesn't summon five elevators, the outcome is the same as pressing it once. Compare that to shouting 'add one more pizza to my order' five times — that genuinely places five separate orders, since each shout is a new instruction, not a repeat of the same one.
Examples
A non-idempotent request made safely idempotent
// Not idempotent: retrying this could charge the customer twice
// POST /payments { amount: 50, userId: 123 }
// Made idempotent with a client-generated key
// POST /payments
// { amount: 50, userId: 123, idempotencyKey: "req-8f3a2b" }
// Server logic:
function handlePayment(request, alreadyProcessed, previousResult, processPayment) {
if (alreadyProcessed(request.idempotencyKey)) {
return previousResult(request.idempotencyKey); // don't redo the charge
}
return processPayment(request); // otherwise process normally, and remember this key's result
}How it works
The client generates a unique key for a given logical operation (not per network attempt — the same key is reused for retries of the same attempt) and sends it along with the request. The server remembers which keys it has already processed and their results; if the same key arrives again, it returns the stored result instead of repeating the underlying effect.
Why does it exist?
Without idempotency, a client that can't tell whether a request actually succeeded (because the response was lost, not because the request failed) has no safe way to retry — retrying risks duplicating the effect, while not retrying risks leaving a legitimately failed operation unresolved. Idempotency removes that dilemma by making retries harmless.
When to use it
Make an operation idempotent whenever it has a real-world effect that would be harmful to duplicate — payments, sending a notification, creating an order — especially for any operation a client might reasonably retry after an uncertain failure.
When not to use it
For an operation that's naturally already safe to repeat (checking a status, reading data, updating a value to a fixed target state) idempotency is often already free — no extra key or tracking is needed. Reserve the extra idempotency-key machinery for operations that genuinely aren't naturally idempotent, like "charge" or "send".
Common mistakes
Assuming GET requests need idempotency protection — reads are naturally idempotent already, since reading the same thing twice changes nothing.
Reusing a fresh idempotency key for every retry attempt instead of the same key for the same logical operation, which defeats the entire purpose.
Forgetting to eventually expire stored idempotency keys, causing unbounded storage growth over time.
Practice exercises
- Easy:
Explain, in your own words, why retrying a payment request without idempotency protection is risky.
- Medium:
Give one example of an operation that's naturally idempotent, and one that isn't, and explain the difference.
- Hard:
Explain why the idempotency key must be generated once per logical attempt by the client, rather than by the server.
Interview questions
What does it mean for an operation to be idempotent?
Performing it multiple times has the exact same effect as performing it once, making it safe to retry without duplicating the result.
Why is idempotency especially important for payment APIs?
Because a client that isn't sure if a payment request succeeded needs a safe way to retry without risking charging the customer twice.
Is a GET request typically idempotent?
Yes — reading the same data multiple times doesn't change anything, so GET requests are naturally idempotent without any extra design work.