The inbox pattern records each incoming message in a local inbox table before processing it. A consumer checks whether the message ID was already handled; if not, it processes the work and marks the row complete in the same transaction.
The problem it solves
Message brokers and HTTP callbacks typically deliver at-least-once. Retries, relay crashes, and network timeouts can deliver the same event twice. Without a deduplication layer, consumers double-charge, duplicate shipments, or create inconsistent state.
The inbox pattern pairs with the outbox pattern: outbox guarantees reliable publish; inbox guarantees reliable consume.
How it works
- Receive a message with a stable message ID (or idempotency key).
- In one local transaction, insert the ID into an
inboxtable (unique constraint on ID). - If the insert succeeds, apply the business change in the same transaction.
- If the insert fails on duplicate key, skip processing. The message was already handled.
This is stronger than ad hoc checks because the uniqueness constraint and business write commit atomically.
BEGIN;
INSERT INTO inbox (message_id, received_at)
VALUES ('evt-9f2a', now());
UPDATE orders
SET status = 'paid'
WHERE id = 'o-123';
COMMIT;On a duplicate delivery, the INSERT violates the unique constraint and the transaction rolls back before any business change runs.
Relationship to idempotency
Inbox deduplication is one way to achieve idempotent consumption. Other approaches include idempotency keys on APIs and upserts keyed by event ID. Choose inbox when you need durable, queryable dedupe state inside the service database.
Trade-offs
- Adds an inbox table and cleanup of processed rows.
- Requires a stable message ID from the producer or broker.
- Does not replace end-to-end ordering guarantees. It only prevents duplicate effects.
- Polling and CDC relays on the outbox side still mean consumers must tolerate redelivery until the inbox marks a message done.
Related reading
See event-driven architecture for the messaging model and webhook reliability patterns for HTTP callback deduplication.
