Filter concepts by levelShowing all levels.

AWS · Idempotency

API Reliability and Idempotency on AWS

The client cannot tell a lost request from a lost response — everything else follows from that

  • The timeout is ambiguousthree realities, one observation
  • Atomic, or it is not idempotentcheck-then-act loses the race
  • Five mechanisms, not onethe natural key decides which
  • Exactly-once effect, not deliverythe second is not on offer

1.What Idempotency Actually Means

An idempotent operation can be retransmitted or retried with no additional side effects. Running it twice leaves the system in the same state as running it once, and the caller gets the same answer either way. That property is what makes retries safe — and without it, every timeout becomes a choice between losing work and duplicating it.

Key features

  • AWS defines an idempotent operation as one where a request can be retransmitted or retried with no additional side effects
  • AWS's preferred approach is to incorporate a unique caller-provided client request identifier into the API contract — EC2 exposes this as `ClientToken`
  • A retry must return a semantically equivalent response, so the caller cannot tell whether it was the first attempt or the fifth
  • Recording the idempotency token and performing the mutation must be one atomic, consistent, isolated and durable operation, or partial state results
  • The service has to keep request history beyond the lifetime of the resource, because a late retry can arrive after the resource is gone
  • Idempotency is a property of the operation as a whole — a handler that writes two rows in two transactions is not idempotent even if each write is

Where the ambiguous timeout shows up

Where the ambiguous timeout shows up
PlaceWhy a retry happensWhat a duplicate costs
A public APIThe client, a proxy, or a mobile network retriesTwo orders, two accounts, two of whatever was created
A payment operationThe gateway times out; the caller retriesA customer charged twice — the most expensive duplicate there is
An SQS consumerThe visibility timeout expires before the handler finishesThe message is processed again by another worker
An asynchronous LambdaLambda retries the invocation on errorThe handler runs twice for one event
An event source mappingA batch is redelivered after a partial failureEvery record in the batch is reprocessed, not just the failed one
A distributed workflowA step is retried after a transient errorThat step's effect is applied twice mid-workflow
The ambiguous timeout, and what it forces

The client sees one thing — no response — in three completely different situations. Idempotency is what makes the same next action correct in all three.

  • A diagram showing one client request that times out, branching into three possible realities.
  • The client sends a request and receives no response. From the client's side, all three of the following look identical.
  • Reality one: the request never arrived. Retrying is necessary.
  • Reality two: the request arrived and succeeded, but the response was lost. Retrying would duplicate the effect — unless the operation is idempotent.
  • Reality three: the request arrived and is still running. Retrying may run it twice concurrently.
  • Below, the conclusion: without idempotency the client must choose between losing work and duplicating it; with idempotency, retrying is correct in all three realities.

Signature

client-supplied key + atomic record-and-mutate + stored response on retry + retention beyond resource lifetime

An idempotent operation can be retried with no additional side effects, because the client cannot tell a lost response from a lost request. Take a client-supplied key, record it and perform the mutation in one atomic transaction, return the same stored response to every retry, and keep the record longer than the resource itself lives.

2.The Mechanisms, and Which One to Reach For

There are five ways to make an operation safe to repeat, and they are not interchangeable. An idempotency key identifies the request; a conditional write makes the first attempt win atomically; deduplication filters repeats within a window; a unique constraint lets the database enforce it; durable state remembers what was already done. Most real designs use two of them together.

Key features

  • A DynamoDB conditional write with `attribute_not_exists(pk)` succeeds only when no item with that key exists; when it fails the response is "The conditional request failed"
  • SQS FIFO queues do not introduce duplicate messages: retrying `SendMessage` within the 5-minute deduplication interval adds no duplicate
  • FIFO deduplication is either content-based — a SHA-256 hash of the message body, excluding attributes — or an explicit message deduplication ID
  • S3 replaces an existing object when the key already exists, so a deterministic object key is itself an idempotency mechanism
  • A unique constraint or a conditional write moves the race into the storage engine, where it is actually atomic
  • Deduplication windows are bounded — SQS FIFO's is five minutes — so anything that can be retried later needs durable state instead

The five mechanisms, side by side

The five mechanisms, side by side
MechanismEnforced byWindowBest for
Idempotency keyYour code plus a unique indexAs long as you retain itCreates over a public API, where no natural key exists
Conditional writeThe database, atomicallyAs long as the item existsDynamoDB writes, claims, and optimistic concurrency
Unique constraintThe database, atomicallyAs long as the row existsRelational creates with a natural key
SQS FIFO deduplicationSQS5-minute intervalProducer-side retries of the same send
Deterministic object keyS3 replace-on-writeUnboundedFile and artifact processing pipelines
Durable stateYour storageWhatever you chooseAnything retried after a bounded window closes

Producer-side and consumer-side are different problems

Producer-side and consumer-side are different problems
AspectProducer-side duplicateConsumer-side duplicate
CauseThe same message is sent twice after a timeoutOne message is delivered or processed more than once
Fixed bySQS FIFO deduplication, within 5 minutesAn idempotent handler — nothing else
Bounded?Yes, by the deduplication intervalNo — a redelivery can happen at any time
Standard queuesNo deduplication at allSame requirement: the handler must be idempotent
Common errorAssuming FIFO makes the consumer safe tooAssuming a visibility timeout prevents reprocessing
Five mechanisms, and where each one belongs

The choice is usually made for you by what identifies the work: a natural key means the storage layer can enforce it, and only the absence of one requires a caller-supplied token.

  • A decision-style diagram of five idempotency mechanisms.
  • Starting question: does something already uniquely identify this work?
  • If yes, and it is a database write: use a conditional write or a unique constraint, such as DynamoDB attribute_not_exists on the primary key. The storage engine enforces it atomically.
  • If yes, and it is an object: use a deterministic S3 key, because writing the same key replaces rather than duplicates.
  • If no, and the caller can supply one: take an idempotency key in the API contract and store it with the result.
  • If the repeat happens within a short window on a queue: use SQS FIFO deduplication, either content-based or with an explicit deduplication ID, within the five-minute interval.
  • For anything that can be retried later than that window: use durable state — a record of what was already done that outlives the resource.

Signature

idempotency key · conditional write · unique constraint · FIFO dedup (5 min) · deterministic key · durable state

Let the storage engine enforce it whenever a natural key exists — a conditional write or unique constraint is atomic and free. Take a client-supplied idempotency key only when nothing natural identifies the request. FIFO deduplication covers producer retries within five minutes and never covers the consumer, which always needs its own idempotency.

3.Never Assume Exactly-Once

Exactly-once delivery is not something a distributed system can offer, because a sender cannot tell a lost message from a lost acknowledgement. What can be built is exactly-once effect: at-least-once delivery plus a handler that produces the same result no matter how many times it runs. Every design that claims otherwise is relying on something being written down somewhere else.

Key features

  • A sender that receives no acknowledgement cannot distinguish a lost request from a lost response, which is why retries exist and why duplicates follow
  • SQS FIFO prevents a duplicate being added to the queue when `SendMessage` is retried within the 5-minute deduplication interval — a producer-side guarantee, not a processing one
  • Standard SQS queues make no deduplication guarantee at all
  • Lambda retries asynchronous invocations, and event source mappings redeliver batches, so a handler runs more than once as normal behaviour
  • S3 event notifications are delivered at least once, so an object-triggered pipeline sees repeats without anything having failed
  • AWS notes that requests can arrive late and from multiple actors, so a service must retain request history beyond the lifetime of the resource itself

What each AWS service actually promises

What each AWS service actually promises
ServiceDeliveryDeduplicationWhat you still owe
SQS standardAt least onceNoneAn idempotent consumer
SQS FIFOAt least once to the consumerProducer sends, within a 5-minute intervalAn idempotent consumer, still
SNSAt least onceNoneIdempotency in every subscriber
EventBridgeAt least onceNoneIdempotency in every target
S3 event notificationsAt least onceNoneDerive identity from the object key
Lambda, asynchronousRetried by the service on errorNoneAn idempotent handler
Lambda event source mappingBatches can be redeliveredNonePer-record idempotency, not per-batch
DynamoDB conditional writeNot applicableNot applicableNothing — this is the mechanism that gives the guarantee
What each layer actually guarantees

Exactly-once delivery

Not available. A sender cannot tell a lost message from a lost acknowledgement, so it must retry, so duplicates exist.

At-least-once delivery

What SQS, SNS, EventBridge, S3 notifications and Lambda event sources actually provide. Assume it everywhere.

Bounded deduplication

FIFO removes duplicate sends within a 5-minute interval. Narrow, useful, and not a processing guarantee.

Exactly-once effect

What you build: a conditional write, a unique key, or stored durable state. This is the only layer under your control.

  1. Exactly-once delivery — Not available. A sender cannot tell a lost message from a lost acknowledgement, so it must retry, so duplicates exist.
  2. At-least-once delivery — What SQS, SNS, EventBridge, S3 notifications and Lambda event sources actually provide. Assume it everywhere.
  3. Bounded deduplication — FIFO removes duplicate sends within a 5-minute interval. Narrow, useful, and not a processing guarantee.
  4. Exactly-once effect — What you build: a conditional write, a unique key, or stored durable state. This is the only layer under your control.

Signature

at-least-once delivery (theirs) + idempotent effect (yours) = exactly-once outcome

Delivery is at least once and you do not control it; effect is exactly once and you do. Every AWS guarantee — FIFO deduplication in particular — narrows one specific, documented window and leaves the consumer's obligation untouched. Write down what each guarantee does not cover, and put a conditional write there.

Remember

  • AWS: recording the idempotency token and the mutating operations must together be atomic, consistent, isolated and durable — one transaction, not three statements.
  • A retry must get a semantically equivalent response, so return the stored result rather than a 409 the client cannot use.
  • SQS FIFO deduplicates SendMessage retries within a 5-minute interval; that is producer-side, and the consumer still needs its own idempotency.
  • Request history has to outlive the resource, because a late retry can arrive after the thing it created has been deleted.

Pro tip

  • Prefer a conditional write over a distributed lock for claiming work: a lock is a lease that can expire mid-work, while a conditional write records the decision durably at the moment it is made.
  • When a duplicate happens, look for the component that behaved correctly rather than the one that broke — a visibility timeout expiring during a slow call is documented behaviour, not a fault.

Next up

  • AWS Senior-Level System Design
  • Messaging — SQS
  • DynamoDB

Sources

  • Making retries safe with idempotent APIs — aws.amazon.com/builders-library/making-retries-safe-with-idempotent-APIs/
  • DynamoDB condition expressions — docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.ConditionExpressions.html
  • Exactly-once processing in Amazon SQS — docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues-exactly-once-processing.html
  • Checked against official AWS documentation 2026-09-04

Spotted a mistake on this page? Tell us.