Idempotency
An operation is idempotent when repeating it produces the same observable result as performing it once. It is the foundation of safe retries in distributed systems.
Definition
Idempotency means that applying an operation multiple times has the same effect on system state as applying it once. In HTTP, GET, HEAD, PUT, DELETE, and OPTIONS are defined as idempotent methods, while POST is not. For non-idempotent operations such as payments and order creation, an idempotency key lets the server recognize a retry and return the original result instead of executing the operation again.
Context and scope
Networks fail after the server commits but before the client receives the response. Without idempotency, the client cannot distinguish “the request never arrived” from “the request succeeded and the response was lost,” so a retry can duplicate the effect. Idempotency is required for safe retries, at-least-once delivery, and webhook processing.
Common misconceptions
- Idempotent means the response is identical — the state effect is identical; the response may differ (for example, a cached original response versus a fresh one)
- PUT is always safe — it is idempotent but still modifies state; safe means read-only
- A unique database constraint is enough — it prevents duplicates but may not return the original successful response to the client
Anti-patterns
- Retrying a POST that creates an order without an idempotency key
- Storing idempotency keys forever without an expiry or storage bound
- Treating an idempotency key as authentication or authorization
Related concepts
Related examples
Authoritative source
Where retries create duplicates
A client sends “create order.” The server writes the order, then the connection drops before the response arrives. The client retries. If the server has no way to recognize the retry, it creates a second order. The bug is not the retry; it is the missing idempotency contract.
Two common implementations
Idempotency key: the client generates a unique key and sends it with the request. The server stores the key together with the result. A repeated key returns the stored result instead of re-executing.
Natural idempotency: the operation is expressed as an upsert or a state assignment, so repeating it converges to the same state:
INSERT INTO accounts (id, balance)
VALUES ($1, $2)
ON CONFLICT (id) DO UPDATE
SET balance = EXCLUDED.balance
RETURNING id, balance;
The upsert is idempotent for the same input. A relative update such as balance = balance + 10 is not.
Keys need a lifetime
Store idempotency keys with a bounded retention period and a unique constraint. Decide what happens when a duplicate arrives while the original is still in flight: return a conflict, wait, or replay the original response. Record the request fingerprint so the same key with a different payload is rejected rather than silently returning an unrelated result.
When to use it
Use idempotency for payments, order creation, webhook processing, message consumption, and any operation a client may retry automatically. Compared to exactly-once delivery, idempotency is usually cheaper and more robust: deliver at least once and make the handler safe to repeat.
Pitfalls
An idempotency key without payload validation can hide a client bug. A key stored without expiry grows without bound. A key used as an authorization token creates a security hole. Treat the key as a retry identifier, not as identity or permission.