Stop 09 · Infrastructure as CodeTopics · 8/9

Idempotency in IaC

Part of the DevOps Roadmap

In short

If running your setup twice breaks something or creates a duplicate, you can never safely rerun it after a failure. Idempotent code gives the same end result whether you run it once or fifty times.

Applying the same IaC configuration multiple times should converge to the same end state without unintended side effects — the same idempotency principle from Phase 5's scripting, now applied to infrastructure.

The mascot presses a lift call button again and again while a single lift door opens.

Think of it like this

The lift call button

Press the lift button once and a lift comes. Press it ten more times out of impatience and still only one lift comes. The button means 'I want a lift here', not 'send another lift'. Idempotent IaC works the same: it states what you want, not what to do.

Watch it happen

Running the same setup twice

Bash script
Server
Ansible

useradd deploy

1/5The first run of a plain script creates the user. Fine so far.

The big ideas

What you need to know

Desired state, not steps

Say 'nginx installed, version X', not 'run apt install'. The tool checks and only acts on the difference.

Safe retries

If a run fails halfway, you just run it again. Idempotent steps that already succeeded are skipped.

Check, then act

Writing your own scripts? Test before changing: does the user exist, is the line already in the file?

Watch the escape hatches

Ansible's shell and command modules and Terraform's local-exec are not idempotent unless you make them so.

See it in code

Walk through the code

bash
1# Not idempotent: second run fails or duplicates2useradd deploy3echo 'export PATH=$PATH:/opt/app' >> /home/deploy/.bashrc4 5# Idempotent: check first, then act6id deploy >/dev/null 2>&1 || useradd deploy7grep -qxF 'export PATH=$PATH:/opt/app' /home/deploy/.bashrc \8  || echo 'export PATH=$PATH:/opt/app' >> /home/deploy/.bashrc

1/3Run twice: useradd errors out, and the PATH line is appended a second time.

Run as root on a throwaway VM or container. In Ansible, the user and lineinfile modules do these checks for you.

Save yourself the pain

Common mistakes

Oops

Reaching for shell: in Ansible because it's quicker to write.

Do this instead

Use the proper module, or add creates:, removes: or changed_when: so Ansible knows when the command really changed something.

Oops

Assuming a tool is idempotent so your code must be too.

Do this instead

Prove it: run everything twice in CI. The second run should report zero changes.

Your mission

The second-run test

~25 min

Quick check

Which of these is idempotent?

Go deeper

  1. 1Apply the same Terraform or Ansible configuration twice and confirm the second run makes no changes.
  2. 2Learn why non-idempotent infrastructure code is dangerous to re-run after a partial failure.
  3. 3Understand this is a core design goal of both Terraform and Ansible, not an accident.

More topics at this stop

Stuck on this topic? Ask an Insider

Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.

Download
InsideEdge