Infrastructure as Code

Infrastructure as code (IaC) is the practice of defining infrastructure in versioned, machine-readable definitions instead of configuring it by hand. A published definition: it “uses DevOps methodology and versioning with a descriptive model to define and deploy infrastructure, such as networks, virtual machines, load balancers, and connection topologies.”

The ambition is stated as an analogy worth holding onto: “just as the same source code always generates the same binary, an IaC model generates the same environment every time it deploys.”

And the problem it was built for has a name. The practice “evolved to solve the problem of environment drift in release pipelines,” where without it “teams must maintain deployment environment settings individually” and “over time, each environment becomes a ‘snowflake,’ a unique configuration that can’t be reproduced automatically.”

The one rule it rests on

Everything else is negotiable; this is not. “To make changes, the team edits the source, not the target.”

Read that as a precondition rather than a best practice. A repository that describes infrastructure is only useful if it is true, and every change made directly in a console makes it less true — silently, and with no error anywhere. A team that keeps the tooling but not the rule ends up with a repository that documents intentions and an estate that nobody can reproduce, which is worse than having neither, because people trust the file.

Which is why the practice is described as “a component of continuous delivery” rather than as a tooling choice. It belongs to the same discipline as building an artifact once: the value comes from a single authoritative description, and every bypass removes some of it.

Two ways to converge, and what that is not

The mechanism underneath is usually called idempotency: “a deployment command always sets the target environment into the same configuration, regardless of the environment’s starting state.”

That quoted sentence is a stronger property than idempotency as normally defined, and keeping them apart prevents two real mistakes. Idempotency says repeating the same operation has the same effect as performing it once. Convergence from an arbitrary starting state says whatever the target looked like before, it ends up matching the definition. The second implies the first; the first does not imply the second.

Two consequences follow, and both come up in practice.

  • Convergence only covers what the definitions mention. A run that is idempotent with respect to the attributes it manages leaves everything else as it found it. So “the tool is idempotent” is not a claim that the environment now matches the definition in every respect — only in the respects the definition addresses. This is the same limit that appears below as the characteristic failure of converging in place.
  • Idempotent is not reversible. Deleting a resource is idempotent — run it again and the resource is still absent, which is the same end state — and it is not undoable. Repeatability says nothing about whether you can get back. A destroy that succeeds twice has still destroyed the data once.

Which separates two questions that get asked together and answered differently. Can I re-run this? — that depends on whether repeating the call can produce a second effect, which an idempotent contract is precisely what rules out: “an idempotent operation is one where a request can be retransmitted or retried with no additional side effects.” Can I undo this? — that depends on whether a copy of the previous state exists anywhere.

The two vary independently, which is why the familiar shorthand about creates and deletes is the wrong rule. What settles each one is a condition rather than the verb.

  • Safe to re-run when the API promises it — through a caller-supplied request identifier, a natural key the service will not duplicate, or an operation that converges on the same result. No identifier does not automatically mean unsafe; it means you have to check what is promised.
  • Safe to re-run a removal additionally requires a stable target. A delete aimed at whatever is currently named X will destroy a different resource if the name has since been reused; one aimed at a specific identifier will not.
  • Reversible when the previous state still exists and nothing outside the resource already acted on the change — a notification sent, an identifier handed to another system, a meter started. Deleting what you just created undoes the resource, not the consequences.

So the useful questions are what exactly the operation targets, what the API promises about repetition, what the current state is, and whether a tested restore path exists for anything that removes.

The definition then names two ways to get there, and this is the most useful sentence in the subject because most tool disagreements are really disagreements about which one you have chosen: “idempotency is achieved by either automatically configuring the existing target, or by discarding the existing target and recreating a fresh environment.”

Converge in placeReplace
What a run doesInspects the target, changes what does not match the definitionBuilds a new instance from a known artifact and swaps it in
Characteristic failureAnything the definitions do not mention stays wrong foreverAnything not captured in the artifact is lost on replacement
Where truth accumulatesOn the host, graduallyIn the artifact, all at once
What it needs to be safeA habit of detecting differences, not only correcting known onesConfidence that nothing valuable lives only on the host

The replacement route is the immutable approach, worked through under golden image. The convergence route is what people usually mean by configuration management, and its weakness deserves emphasis: convergence only covers what the definitions mention, so a package installed by hand two years ago is not mentioned anywhere and no run removes it. That residue is configuration drift.

Most estates run both. That is fine as long as the boundary is written down — the image owns what every host has, the configuration layer owns what varies. Where it is unstated, the same setting gets managed twice and the last run wins.

Three states, and why they disagree

Adopting IaC does not reduce the number of answers to “what do we have.” It gives you three, and the practice is largely about keeping them aligned.

  • The declaration — what the code says should exist.
  • The record — what the tool believes exists, and which real object matches which declared resource. Where that record lives varies by tool: Terraform hands it to you as an infrastructure state file you store and protect, while Bicep advertises “no state or state files to manage: Azure stores all states.” The record exists either way; who is responsible for it does not.
  • The reality — what the provider actually has, including anything created outside the tool.

Almost every difficulty in this area is one of the three drifting from another, and naming which pair has diverged is usually enough to know what to do. Declaration against reality is drift, corrected by applying. Record against reality is a lost or stale record, corrected by refreshing or importing. Declaration against record is an ordinary pending change.

What it does and does not give you

The benefits worth expecting are concrete. Environments become reproducible, so you can “provision multiple test environments reliably on demand” and “test applications in production-like environments early in the development cycle.” Changes become reviewable, because a change is a diff. And the description becomes the documentation, which is the only kind that stays current.

Four expectations to correct before adopting it.

  • It does not make changes safe. It makes them repeatable and reviewable. A destructive change expressed in code is still destructive, and re-running it does not undo it.
  • It does not manage what you did not declare. Resources outside the definitions are invisible to it, which means adoption on an existing estate starts with an inventory rather than with a file.
  • It does not remove the need for design. Encoding a poorly structured network makes the poor structure reproducible and harder to change, because now it has consumers.
  • It is not free of operational burden. The record needs storing, locking, and backing up; the tooling needs upgrading; and secrets have to be kept out of both the code and the record. That last one is the most commonly discovered late — see secrets management.

Where this sits in a wider setup: the account and organizational structure that IaC operates inside is a separate design, covered under landing zone, and expressing the rules that constrain what may be created is policy as code. How state, review, module boundaries, and secrets fit together in practice is worked through in The File That Says What Exists.

Reference: Microsoft Learn, What is Bicep?; Microsoft Learn, What is infrastructure as code (IaC)?; Malcolm Featonby, Making retries safe with idempotent APIs (Amazon Builders’ Library) (all checked September 2026).


Discover more from Insightful Data Lab

Subscribe to get the latest posts sent to your email.

Similar Posts

Questions, corrections, or additional insights?

This site uses Akismet to reduce spam. Learn how your comment data is processed.