Push a light switch ten times. You end up exactly where you started: the light is on, or it is off. The tenth press is no different in outcome from the first. The result does not accumulate.
Now ring a doorbell ten times. Someone inside hears ten rings. Each press adds to the total. The result accumulates with every repetition.
One operation is safe to repeat without changing the final state. The other is not. That distinction has a name in computer science: idempotency. And once you know what it means, you start seeing it everywhere: in payment systems, in login flows, in the automations you build and the APIs you call.
What the word actually means
An operation is idempotent if applying it multiple times produces exactly the same result as applying it once. The word comes from Latin: idem meaning "the same" and potens meaning "power" or "effect." The same power, no matter how many times you apply it.
Mathematicians have used the term for centuries (multiplying any number by one is idempotent: 5 x 1 x 1 x 1 is still 5). Engineers borrowed it because the property turns out to matter enormously when networks are involved.
A non-technical definition that holds up: an idempotent action is one where "do it again" is the same as "already done."
Where you have already run into it without knowing
The "unsubscribe" button at the bottom of a marketing email is a good example of a well-designed idempotent operation. Click it once and you are removed from the list. Click it again, from the same email, a week later: you are still not on the list. The second click does not subscribe you again or generate an error. The outcome is identical. That is idempotency working as intended.
Compare this to a standard "add to cart" button. Click it five times on the same item and you have five of that item in your cart. Five presses, five distinct results. Not idempotent. Whether that is the right design for a shopping cart is a separate question (usually yes), but it illustrates the point: the same action applied repeatedly has a compounding effect.
A password reset link is a more subtle case. A well-built one can only be used once. The moment you click it and set a new password, the link is invalidated. Clicking it again does nothing. This is idempotent from the perspective of your account state: whether you click once or ten times, the end result is the same (your password is reset, your account is in one defined state). The link is single-use not because of laziness but because making it idempotent is the safer design.
Why network failures make this unavoidable
Most of the time, you do not think about any of this because things just work. The button does what it says. The request reaches the server. The server responds. Done.
But the internet is not a telephone line. Between your phone and a payment processor's server, there are dozens of network hops, routers, load balancers, and firewalls. Any of them can drop a packet. Your connection can stall for three seconds right after the server processes your request but before it sends back the confirmation. Your browser, seeing no response after a timeout, retries. Now the server has received the same payment request twice.
This is not a bug. It is designed behavior. Retry logic is part of how reliable systems are built. The HTTP spec specifies which methods are safe to retry and which are not. The problem arises when a non-idempotent operation (like creating a charge) is retried without any protection against duplication.
This is exactly how people get charged twice for a single order, how duplicate records appear in databases when a form is submitted during a slow network moment, and how the same email gets sent twice when a webhook fires and the delivery confirmation does not arrive cleanly.
The failure mode is not the retry. The retry is the right behavior. The failure mode is building an operation that cannot tolerate being repeated.
How engineers build this protection in
The most common tool is an idempotency key: a unique string that you generate on the client side and send along with the request. When the server receives the request, it stores the key. If a second request arrives with the same key, the server returns the original result without processing the operation again.
Stripe's payment API is a widely used example of this pattern. When you create a charge, you can include an Idempotency-Key header. Stripe stores it for 24 hours. Any duplicate requests with the same key return the original response, including the original charge result, without creating a second charge. If the key is different, it is treated as a new request.
The same pattern appears in workflow automation tools. Most webhook processors (including those built on Zapier and n8n) have deduplication options: you designate a field as the unique identifier for an event, and if the same event arrives twice within a window, the second one is discarded. This matters when a source system fires a webhook and, not receiving a 200 confirmation quickly enough, fires it again.
At the database level, the equivalent is an "upsert" operation: insert the record if it does not exist, update it if it does. Running an upsert twice with the same data produces the same result as running it once. A plain insert run twice creates a duplicate.
The question worth asking before you ship
You do not need to memorize the formal definition to use this concept. The useful version is a single question: what happens if this runs twice?
Ask it before you build any operation that has a real-world consequence: charging a card, creating an account, sending an email, writing a record to a database, triggering a workflow. If the answer is "the same as if it ran once," you are in good shape. If the answer is "it creates two charges / two records / two emails," you have more design work to do before it ships.
The doorbell and the light switch are not just a cute analogy. They represent a genuine fork in the road every time you design something that connects to the internet. Doorbells are sometimes exactly what you want. A button that adds an item to a cart should add the item each time you press it. But when the action has permanent consequences and networks are unreliable, the light switch is usually the right model: press it ten times, get the same result as pressing it once.
Build the light switch. Test what happens when it gets pressed twice.
Sources
- Stripe: Idempotent Requests (stripe.com)
If you are building automations or integrations and want to think through retry logic or deduplication design, drop me a line.
Comments