Overview
An operation is idempotent when repeating it with the same input changes nothing beyond the first run. Design every retried operation this way, including webhook handlers, queue consumers, and payment calls, because networks and queues deliver duplicates. An idempotency key or an upsert usually costs one column.
Rules
- HTTP:
GET,HEAD,OPTIONS,PUT, andDELETEare idempotent by definition;POSTandPATCHare not. Make aPOSTretry-safe with anIdempotency-Keyheader: the server stores the key with the first response and replays it for repeats (a convention popularized by Stripe). - A key must be unique per logical operation, and reuse with a different payload must be rejected.
- Databases:
UPDATE ... SET status = 'paid'is idempotent;SET balance = balance - 5is not. Use upserts orON CONFLICT DO NOTHINGkeyed on a request or message ID. - Consumers: record the processed message ID in the same transaction as the side effect.
INSERT INTO payments (idempotency_key, amount_cents) VALUES ($1, $2)
ON CONFLICT (idempotency_key) DO NOTHING;Related
- side-effect: the effects that retries must not duplicate.
- immutable-data: immutable inputs simplify idempotency.
- webhooks: webhook handlers must be idempotent.
- http-status-codes: HTTP method semantics.
- general-principles: the broader design principles.