Idempotency: The Word That Changed How I Write Scripts

Why the most useful idea in automation is making a script safe to run twice — and how designing for re-runs instead of one perfect pass quietly fixed most of my reliability problems.

Idempotency: The Word That Changed How I Write Scripts

For years I wrote automation the way most people do: as a sequence of steps that assumed a clean starting point and ran straight through to the end. Create this, configure that, deploy the other. It worked beautifully the first time and was a small disaster every time after, because the real world is never a clean starting point. The script would hit something that already existed, error out halfway, and leave the system in a state that was neither the old one nor the new one — a mess I then had to untangle by hand. The fix was not better error handling. It was a single idea with an awkward name.

Idempotency means an operation produces the same result whether you run it once or a hundred times. Designing for it, instead of for one perfect pass, quietly fixed more of my reliability problems than any other change I have made to how I write code.

A script you can only safely run once is not automation. It is a manual procedure that happens to be typed out, and the first time it fails halfway you find out the difference.

The brittle way and why it fails

The brittle script is a list of imperative actions: do this, then do this, then do this. It assumes each step starts from the state the previous step left behind, and it assumes every step succeeds. Both assumptions are false often enough to matter. Run it on a system where step one’s work already exists and it errors. Run it after a previous attempt died at step three and it either refuses to start or, worse, redoes steps one and two in a way that conflicts with what is already there.

The deeper problem is that a one-shot script has no concept of the current state. It only knows the actions it wants to take, not the world it is taking them in. So it cannot tell the difference between “this needs doing” and “this is already done”, and that single blindness is the source of almost all the fragility. Every “it failed halfway and now everything is broken” story is really a story about a script that did not know where it was.

The idempotent way: declare the destination

The shift is from describing actions to describing the desired end state, and then making each step check reality before changing it. Instead of “create the directory”, you write “ensure the directory exists” — which does nothing if it already does, and creates it if it does not. Instead of “add the line to the config”, you write “ensure the config contains the line.” Each step asks is the world already how I want it? and acts only on the gap.

# Brittle: assumes a clean start, explodes on the second run
os.mkdir("/srv/app/data")          # FileExistsError if it exists
add_line("/etc/app.conf", setting)  # duplicate on every run

# Idempotent: describes the destination, safe to run forever
os.makedirs("/srv/app/data", exist_ok=True)   # no-op if present
ensure_line("/etc/app.conf", setting)          # adds only if missing

Written this way, the script can be run twice, ten times, or resumed after a failure, and it always converges on the same correct end state. A step that is already done is a no-op. A step that failed last time gets completed this time. The script stops being a fragile sequence and becomes a description of where you want to end up, with the path to get there computed against reality each run.

Why this changes everything downstream

Once scripts are idempotent, a whole category of operational anxiety disappears. You can re-run after a failure without fear, because re-running is safe by construction — that is the defensive instinct I apply to n8n flows, pushed down into the scripts themselves. You can run the same automation across many machines in different states and trust them all to converge. And you can run it routinely, as a way of asserting “the world should look like this”, catching and correcting drift every time rather than only when something visibly breaks.

This is the foundation under infrastructure-as-code and under repeatable customer health checks, and it is no accident that the same idea sits beneath both. A health check that grades a tenant has to produce the same result run twice in a row, or it is not a check, it is a mood. Idempotency is what makes “run it again and trust the result” a reasonable thing to say. Without it, every re-run is a gamble.

What it costs

The honest cost is that idempotent code is more work to write than the brittle version, because every step has to check the current state before acting rather than barging ahead. “Ensure it exists” is genuinely more thinking than “create it.” You have to consider what already-done looks like for each operation, and handle the partial-completion cases the one-shot script ignored. It is more upfront effort for code that, on its successful first run, looks identical in its effect.

But that cost is paid once, at writing time, and it buys you reliability forever. The brittle script saves you effort exactly once — the first time you run it — and charges interest on every run after. I have never regretted making a script idempotent. I have repeatedly regretted not bothering.

The word that stuck

I keep coming back to how much changed from internalising one awkward word. Before, I wrote automation as a hopeful sequence and braced for the cleanup when it failed partway. After, I write it as a description of the destination, safe to run as many times as I like, converging on the same state no matter where it starts. The scripts got more boring and far more trustworthy, which is exactly the trade I want from anything I am going to rely on.

If you take one habit from this, make it the reflex of asking, before every step you automate: what happens if this runs again? If the answer is “it breaks” or “it duplicates”, you have written a manual procedure in disguise. Make it a no-op when the work is already done, and you have written automation you can actually trust — which is the only kind worth having.