Design Patterns

Idempotency

Understanding idempotency for safe retries and reliable systems.

3 min readConcepts · System Design

What is Idempotency?

An operation is idempotent if performing it multiple times produces the same result as performing it once. This is critical for building reliable distributed systems where retries and duplicate messages are common.


Examples

OperationIdempotent?Why
GET /users/123YesReading doesn't change state
DELETE /users/123YesDeleting twice = same result
PUT /users/123 (name: "Alice")YesSets to same value each time
POST /ordersNoCreates new order each time
Increment counterNoEach call changes the value

Why Idempotency Matters


Idempotency Keys

How It Works

Implementation

async function handlePayment(req, res) {
  const idempotencyKey = req.headers['idempotency-key'];

  // Check if we've seen this request before
  const existing = await redis.get(`idem:${idempotencyKey}`);
  if (existing) {
    return res.json(JSON.parse(existing));
  }

  // Process the payment
  const result = await processPayment(req.body);

  // Store the result (TTL: 24 hours)
  await redis.set(
    `idem:${idempotencyKey}`,
    JSON.stringify(result),
    'EX', 86400
  );

  return res.json(result);
}

Making Operations Idempotent

Database Writes

-- Non-idempotent: creates duplicate
INSERT INTO payments (user_id, amount) VALUES (1, 100);

-- Idempotent: uses unique constraint
INSERT INTO payments (user_id, amount, idempotency_key)
VALUES (1, 100, 'abc-123')
ON CONFLICT (idempotency_key) DO NOTHING;

Message Processing


Strategies

StrategyHowBest For
Idempotency KeyClient-generated unique keyAPI requests
Natural KeyUse business identifierOrder processing
UpsertINSERT ON CONFLICT UPDATEDatabase writes
Deduplication tableTrack processed IDsMessage consumers
Conditional writeCheck version/ETagConcurrent updates

Common Patterns

Stripe's Approach

POST /v1/charges
Idempotency-Key: unique-key-123
Content-Type: application/json

{
    "amount": 2000,
    "currency": "usd"
}
  • Keys expire after 24 hours
  • Responses are cached and replayed
  • Different request body with same key returns error

At-Least-Once + Idempotency

Guarantees exactly-once semantics even with at-least-once delivery.


Best Practices

  1. Generate keys client-side using UUIDs
  2. Store results with TTL (don't keep forever)
  3. Validate request body matches for same key
  4. Make the check atomic with the operation
  5. Use natural keys when available (order ID, transaction ID)

Interview Tips

  • Explain why idempotency matters for retries
  • Know HTTP method idempotency (GET, PUT, DELETE = yes; POST = no)
  • Describe idempotency key pattern (Stripe example)
  • Discuss at-least-once + deduplication = exactly-once
  • Mention database strategies (upsert, unique constraints)

Finished reading?

Mark it done to track your progress in Concepts.