The Simple Definition
An operation is idempotent if applying it multiple times has the same effect as applying it once. The result after the first call is the same as the result after any subsequent call with the same inputs.
A good everyday example: setting the thermostat to 21°C is idempotent. Whether you press the button once or five times, the result is the same. Incrementing the temperature by 1°C each time is not — each press changes the outcome.
HTTP Methods and Idempotency
HTTP defines idempotency as part of its method semantics:
- GET — idempotent. Reads do not change server state.
- PUT — idempotent. Setting a resource to a specific value produces the same state no matter how many times you call it.
- DELETE — idempotent. The second delete of an already-deleted resource returns 404, but the server state (the resource is gone) is the same.
- POST — not idempotent by default. Each call typically creates a new resource or triggers an action. Two POST requests to
/paymentsusually mean two charges.
PATCH is ambiguous — it depends on whether the patch operation is absolute or relative.
Why Retries Require Idempotency
In distributed systems, network calls can fail in two ways: the request never arrived, or the request succeeded but the response was lost. From the caller's perspective, these look identical — a timeout or connection error. The only safe response is to retry.
If the operation is not idempotent, that retry is dangerous. A payment that timed out may have already been charged. Retrying processes the payment again. The customer pays twice.
If the operation is idempotent — or made idempotent via an idempotency key — retrying is safe. The server detects the duplicate and returns the original result without re-executing the action.
Idempotency Keys
For operations that are not naturally idempotent (like POST to create a payment), you can add idempotency by using a client-generated unique key. The caller generates a UUID or similar token, sends it as a request header (often Idempotency-Key), and the server stores the result of the first execution.
On a retry with the same key, the server looks up the stored result and returns it without re-executing. On a fresh key, it executes normally. Stripe, Braintree, and most payment APIs work this way.
The important details:
- keys must be scoped to the operation type, not reused across different actions
- keys should expire after a reasonable window (hours to days, not forever)
- the server must store the result durably so it survives a crash between execution and response
Idempotency in Distributed Workflows
Beyond APIs, idempotency matters anywhere work can be retried or replayed:
- Message queues: a consumer crash mid-processing means the message is redelivered. If the handler is not idempotent, the work runs twice.
- Scheduled jobs: a job triggered by a distributed scheduler may fire more than once if the scheduler retries on uncertainty. Idempotent job logic handles duplicates safely.
- Database migrations: migration scripts that check "does this column exist before adding it" are idempotent. Those that blindly add columns are not.
- Distributed locks: lock acquisition attempts may be retried after a timeout. The lock service must ensure a retry for the same caller does not grant two locks.
What Good Idempotent Design Looks Like
- operations use absolute state assignments, not relative increments, where possible
- non-natural idempotent actions accept and store an idempotency key
- deduplication windows are defined and enforced
- retries are safe by default — callers should not need to know whether a prior attempt succeeded
- at-least-once delivery is assumed; idempotency absorbs the duplicates
What to Read Next
For a broader view of my distributed systems and API work, see Distributed Systems Engineering: Correctness, Coordination, Reliability.
Idempotency and distributed locks are closely related — locks prevent concurrent execution of the same operation across workers. See What Is a Distributed Lock? (With Examples) for how lock semantics and fencing tokens protect critical sections. For a broader production framing of assumption failures around retries and partial completion, read The Fallacies of Distributed Computing Still Break Modern Systems. For overload and retry amplification under load, see Backpressure in Distributed Systems: Stability, Correctness, and Graceful Degradation.