Academy · Messaging & Async

Idempotency & exactly-once

Networks retry. The same "charge card" message can arrive twice. Now you've double-charged.

2 min read·8 sections
Open the interactive version → diagrams, practice & more

The problem

Networks retry. The same "charge card" message can arrive twice. Now you've double-charged.

The idea

Make operations idempotent: applying them twice has the same effect as once.

How it works

Make operations idempotent so applying them twice equals once. The client attaches an idempotency key; the server atomically records "key → result" and on a duplicate returns the stored result instead of redoing the work. *Exactly-once delivery is impossible over an unreliable network, so the real recipe is at-least-once delivery + idempotent processing = exactly-once effect*. Enforce it where it's atomic — a unique constraint or INSERT … ON CONFLICT — not a check-then-act two concurrent retries can both pass.

The tradeoff

You must store and check keys with a retention window long enough to outlive retries but bounded so it doesn't grow forever. The transactional-outbox pattern closes the sibling gap (DB write commits but the event publish fails) by writing the event in the same transaction and relaying it later. The cost is bookkeeping; the payoff is the only safe way to handle the retries that will happen.

In the wild

Stripe's API uses an Idempotency-Key header for exactly this reason.

Deep dive

Flow

  1. Client generates an idempotency key per logical operation.
  2. Server atomically records key → result (unique constraint).
  3. A duplicate key returns the stored result, skipping the work.
  4. Expire keys after a window that safely outlives retries.

Watch for

  • Check-then-act lets two concurrent retries both slip through — make it atomic.
  • Key retention too short → a late retry double-applies.
  • DB write + separate publish can diverge — use a transactional outbox.

Common trap

Say exactly-once effect = at-least-once delivery + idempotent apply, enforced atomically.

Common questions

What problem does Idempotency & exactly-once solve?

Networks retry. The same "charge card" message can arrive twice. Now you've double-charged.

How does Idempotency & exactly-once work?

Make operations idempotent so applying them twice equals once. The client attaches an idempotency key; the server atomically records "key → result" and on a duplicate returns the stored result instead of redoing the work. Exactly-once delivery is impossible over an unreliable…

What are the tradeoffs of Idempotency & exactly-once?

You must store and check keys with a retention window long enough to outlive retries but bounded so it doesn't grow forever. The transactional-outbox pattern closes the sibling gap (DB write commits but the event publish fails) by writing the event in the same transaction and…

Where is Idempotency & exactly-once used in production?

Stripe's API uses an Idempotency-Key header for exactly this reason.

Part of Academy on SystemLore — system design explained with 148 deep topics, interactive diagrams, and a build-it-yourself game. Browse the glossary and "X vs Y" comparisons, or build this one →