What is Infrastructure as Code (IaC)? A plain-English guide
Instead of clicking through a portal to build your cloud, you write down what you want in a file and let a tool build it. That one move — infrastructure described as code — is what makes cloud environments repeatable, reviewable, and safe to rebuild.
New to cloud? CAMPUX is a free, build-first course. Start here →
Infrastructure as Code (IaC) is the practice of defining and provisioning your cloud infrastructure — networks, virtual machines, storage, databases — with declarative code and configuration files instead of clicking through a portal. Because those files live in version control, every change is repeatable, reviewable, and rebuildable, and the same file produces the same environment every time. That is the whole idea in one breath. The rest of this note is what that actually means on a real team, and the concepts most tutorials skip over.
Why this matters once more than one person touches the cloud
The first time you build something in the Azure portal, clicking feels fine. The problem shows up later. Six months on, nobody remembers whether the production storage account has soft-delete turned on, because someone toggled it by hand one afternoon and never wrote it down. Your staging environment and your production environment have quietly diverged — that gap is called configuration drift, and it is where a scary share of outages come from.
IaC fixes this by making the file the source of truth. On a real team that buys you three things you cannot get from a portal:
- Repeatability. Spin up an identical environment for dev, test, and prod from the same file. No "works in staging, breaks in prod."
- Review. Infrastructure changes go through a pull request, so a teammate reads the diff before it hits production — the same way application code does.
- History. Git tells you who changed the firewall rule, when, and why. When something breaks at 2am, that history is the difference between a five-minute fix and a long night.
None of that is exotic tooling. It is the ordinary discipline of software — version control, code review, a build pipeline — pointed at your infrastructure instead of your app.
The concepts tutorials skip
Most "getting started" guides throw a template at you and move on. The ideas that actually make IaC click are three, and they are worth slowing down for.
Declarative vs imperative
An imperative approach is a list of steps: create this, then attach that, then set this flag. A shell script is imperative. A declarative approach describes the end state you want — "a storage account named X, in this region, with these settings" — and lets the tool work out how to get there. Bicep, Terraform, and ARM are declarative. You are not writing instructions; you are writing a description, and the tool computes the difference between what exists and what you asked for.
Idempotency
Idempotency is the payoff of being declarative: you can run the same file ten times and the result is identical to running it once. If the storage account already exists and matches, the tool does nothing. If someone changed it by hand, the tool changes it back. This is exactly why IaC is safe to run on a schedule and a raw provisioning script is not — run a "create" script twice and you get an error or a duplicate; apply an IaC file twice and you get the same environment, calmly.
State
To know what to create, change, or leave alone, the tool needs to know what already exists. That record is called state. This is the single biggest difference between the Azure tools, so it is worth being precise: with ARM and Bicep, Azure Resource Manager is the state — Azure already knows what is deployed, so there is no separate file to manage. With Terraform, you own a state file that Terraform maintains, and you must store it somewhere safe and shared (a storage account, typically) so your whole team works from the same picture. Losing or corrupting that state file is a genuine failure mode, and it catches people out.
IaC is not "just scripts." A PowerShell script that creates resources is automation, and automation is good — but it is imperative and usually not idempotent. Run it twice and it errors or duplicates. IaC's declarative, idempotent, state-aware model is what makes it something you can trust to run continuously in a pipeline, not a one-shot you babysit. If you take one thing from this note, take that distinction.
Before and after: the same job, two ways
Say you need a storage account. The portal way is a sequence of clicks nobody records; the IaC way is a few lines someone can read, review, and re-run. Here is the contrast at a glance.
| Doing it in the portal | Doing it as code |
|---|---|
| Open the portal, search "Storage accounts," click Create, fill five wizard tabs, pick options from memory, click through, wait. | Write ~10 lines of Bicep describing the account, commit it, and run one deploy command. |
| No record of what you chose. The next person guesses or clicks around to check. | The file is the record. Anyone reads it in ten seconds. |
| Need a second identical one for staging? Repeat every click and hope you match it. | Copy the file, change the name, deploy. Identical by construction. |
Describe the end state. Commit the file. Let the tool make reality match it.
The Azure IaC tools, compared
Four names come up constantly. Here is how they actually differ, so you can pick without reading four docs sites.
| Tool | Language | State | Best for |
|---|---|---|---|
| ARM templates | JSON (verbose, native to Azure) | Managed by Azure Resource Manager — no separate file | Azure-only teams that need the raw native format; increasingly a compile target rather than something you hand-write. |
| Bicep | Bicep DSL — clean, readable; compiles to ARM | Managed by Azure Resource Manager — no separate file | Azure-only teams who want ARM's power without the JSON pain. The default choice on modern Azure. |
| Terraform | HCL (HashiCorp Configuration Language) | Its own state file you store and manage | Multi-cloud or hybrid teams; one language and workflow across Azure, AWS, GCP, and more. |
| Pulumi / Ansible | Pulumi: real languages (Python, TypeScript). Ansible: YAML playbooks | Pulumi: state like Terraform. Ansible: largely stateless, config-focused | Pulumi for teams who want IaC in a language they already know; Ansible for configuration management and provisioning of servers. |
The short version: if you are all-in on Azure, learn Bicep. If you touch more than one cloud, learn Terraform. Everything else is a variation on those two ideas, and once you understand declarative, idempotency, and state, switching between them is mostly syntax.
What it actually looks like
Enough description — here is real IaC. This Bicep file creates a storage account. Read it top to bottom; it says what it is:
// storage.bicep — a locally-redundant storage account param location string = resourceGroup().location param storageName string resource stg 'Microsoft.Storage/storageAccounts@2023-01-01' = { name: storageName location: location sku: { name: 'Standard_LRS' } kind: 'StorageV2' properties: { minimumTlsVersion: 'TLS1_2' allowBlobPublicAccess: false } }
Deploy it with one command — az deployment group create --template-file storage.bicep --parameters storageName=campuxdata01 — and Azure builds exactly that. Run it again and nothing changes, because the account already matches. Change allowBlobPublicAccess to a new value, commit the diff, re-deploy, and only that one property updates. That is the entire loop: edit the description, apply, reality follows.
The Terraform version of the same thing is a handful of HCL lines in a resource "azurerm_storage_account" block — different keywords, identical idea. If Bicep makes sense, Terraform will too.
Where to go from here
You now have the mental model: IaC is describing infrastructure declaratively in versioned files, so the cloud becomes repeatable, reviewable, and rebuildable. The concepts that make it real are declarative thinking, idempotency, and state — get those and the tools are just syntax. The next honest step is to write one file that creates one resource and deploy it twice, so you feel idempotency with your own hands rather than reading about it.
Questions people also ask
What problem does Infrastructure as Code solve?
IaC solves configuration drift, unrepeatable environments, and infrastructure changes that nobody reviewed. When your infrastructure lives in versioned files, every environment is built the same way, every change goes through code review and version history, and you can rebuild or replicate an environment on demand instead of remembering which buttons you clicked in the portal last quarter.
What is the difference between ARM, Bicep, and Terraform?
ARM templates are Azure's native JSON format — powerful but verbose. Bicep is a cleaner Azure-only language that compiles down to ARM, with no separate state file because Azure Resource Manager tracks state for you. Terraform is a third-party tool that works across Azure, AWS, and many other providers using its own HCL language and its own state file that you must store and manage. Pick Bicep if you are Azure-only, Terraform if you are multi-cloud.
Is Infrastructure as Code hard to learn?
The syntax is easy — a Bicep or Terraform file that creates a storage account is a dozen readable lines. The genuinely new ideas are declarative thinking (you describe the end state, not the steps), idempotency (running the same file twice is safe), and state (how the tool knows what already exists). Grasp those three concepts and the tools follow quickly.
Is Infrastructure as Code just scripting?
No. A shell or PowerShell script is imperative — it runs commands step by step and will fail or duplicate resources if you run it twice. IaC is usually declarative: you describe the infrastructure you want, and the tool figures out what to create, change, or leave alone to reach that state. That difference — idempotency — is why IaC is safe to run repeatedly and a raw provisioning script is not.