In any distributed automation, failure is not an exception to be avoided but a condition to be designed for. Networks time out, processes restart, and webhooks are redelivered. The thesis of this article is that the property which makes such systems trustworthy is idempotency: the guarantee that performing an operation more than once produces the same effect as performing it once. Without this property, every retry becomes a hazard; with it, retries become a routine recovery mechanism rather than a source of corruption.
What Idempotency Means
An operation is idempotent if applying it repeatedly with the same input leaves the system in the same state as a single application. Setting a user’s status to “active” is idempotent: whether the instruction arrives once or five times, the end state is identical. Incrementing a counter is not idempotent: each application changes the result. The distinction is not about whether an operation has an effect, but about whether repeating it adds further effect beyond the first.
This concept is formalised in the semantics of HTTP methods. As documented by MDN, GET, PUT, and DELETE are defined as idempotent, while POST is not. A PUT that replaces a resource with a given representation yields the same resource regardless of how many times it is sent. A DELETE leaves the resource absent whether issued once or repeatedly. POST, by contrast, is intended to create or process anew on each call, which is precisely why duplicate POST requests are a classic cause of doubled orders and duplicated records.
Why Retries Are Inevitable
The motivation for idempotency is that you cannot prevent retries; you can only make them safe. Consider a request that succeeds on the server but whose response is lost in transit. The client, observing no confirmation, retries. The server now receives the same instruction twice. If the underlying operation is not idempotent, the second execution causes harm: a second charge, a second email, a second inventory deduction.
Message queues and webhook systems compound this. Most operate under at-least-once delivery semantics, meaning a message may be delivered more than once by design. An automation that assumes exactly-once delivery is built on a guarantee the infrastructure does not provide. The only robust response is to make the consumer indifferent to duplication.
Patterns for Achieving Idempotency
Several techniques make non-idempotent operations safe to repeat. The most general is the idempotency key: the caller attaches a unique identifier to the request, and the server records which keys it has already processed. On encountering a known key, the server returns the original result rather than performing the action again. Payment processors expose this pattern explicitly, and it can be implemented for any internal operation with a durable record of processed keys.
A second pattern is the conditional write. Rather than blindly inserting a record, the operation checks for the existence of a matching record first, or relies on a database uniqueness constraint to reject duplicates. An “upsert” that updates an existing row or creates one if absent expresses the desired end state declaratively, which is inherently safer to repeat than an unconditional insert.
A third approach is to model operations as state transitions guarded by the current state. Marking an order as “shipped” only if it is currently “paid” ensures that a repeated instruction has no further effect once the transition has occurred. This converts an imperative action into an idempotent assertion about the desired state.
Designing the Boundary
Idempotency must be enforced at the point where effects become durable, not merely at the entry of the system. Validation, logging, and transformation upstream do not protect a downstream database from a duplicated write. The discipline is to identify every side-effecting boundary and ensure that each one either uses a naturally idempotent operation or is protected by a key or constraint.
Conclusion
Idempotency is the property that lets an automation recover from failure by simply trying again. Because retries are an unavoidable consequence of unreliable networks and at-least-once delivery, every operation that mutates state should be made safe to repeat, whether through idempotency keys, conditional writes, or state-guarded transitions. The HTTP method semantics offer a useful mental model, but the underlying obligation extends to every part of a system. Building for repeatable execution is not an optimisation; it is a precondition for reliability.