DevOpsAdvanced

Infrastructure as Code: Why Terraform Won

What Infrastructure as Code actually solves, and why Terraform became the default choice over cloud-specific tools like CloudFormation.

DevFieldGuideJune 13, 2026 (updated July 26, 2026)6 min read
Share:

Infrastructure as Code (IaC) means defining servers, networks, and databases in version-controlled configuration files instead of clicking through a cloud console — and Terraform became the tool most teams default to for it, for specific, non-arbitrary reasons.

What problem IaC actually solves

Before IaC, infrastructure was configured by hand through a console, or via ad hoc scripts — meaning there was no single source of truth for what your infrastructure actually looked like, no code review for infrastructure changes, and no reliable way to reproduce an environment (staging that's supposed to mirror production, but doesn't, because someone clicked a setting six months ago and never documented it).

hcl
# main.tf
resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"
 
  tags = {
    Name = "web-server"
  }
}

This file, checked into Git, is the definition of that server. Change the file, run terraform apply, and the infrastructure updates to match — the same review, diff, and audit trail you already use for application code now applies to infrastructure too.

Why Terraform specifically, over cloud-native tools

Every major cloud has its own native IaC tool — AWS has CloudFormation, Azure has ARM/Bicep, GCP has Deployment Manager. Terraform (from HashiCorp) is cloud-agnostic by design, using providers as a plugin layer:

hcl
provider "aws" {
  region = "us-east-1"
}
 
provider "cloudflare" {
  api_token = var.cloudflare_token
}

One Terraform configuration can define AWS resources, Cloudflare DNS records, a Datadog monitor, and a GitHub repository setting, all in the same declarative language, tracked in the same state. A team using CloudFormation for AWS infrastructure still needs a completely different tool and syntax the moment they touch a non-AWS service — Terraform avoids that fragmentation.

AspectTerraformCloud-native (CloudFormation, ARM, etc.)
Provider scopeMulti-cloud, via a plugin/provider modelLocked to one cloud's own services
Day-one feature supportCan lag behind the newest cloud featuresAlways current with its own platform
Best forMulti-cloud or multi-SaaS teamsSingle-cloud teams wanting day-one access to new features

The core mental model: state

Terraform keeps a state file recording what it believes currently exists. Every terraform plan compares your configuration against that state (and the actual cloud provider) to compute exactly what needs to change:

bash
terraform plan   # shows what WOULD change, without changing anything
terraform apply  # actually makes the change

terraform plan is what makes IaC trustworthy in practice — you see the exact diff (2 resources to add, 1 to change, 0 to destroy) before anything touches real infrastructure, the same review-before-merge instinct developers already have for code.

Where teams get burned

Manual changes outside Terraform. If someone changes a resource by hand in the cloud console, Terraform's state no longer matches reality — the next plan either shows a confusing diff trying to "fix" the manual change, or (worse) Terraform overwrites it without anyone realizing. The rule that makes IaC actually work: once a resource is managed by Terraform, all changes to it go through Terraform, no exceptions.

State file handling. The state file needs to be shared safely across a team (typically stored remotely — S3 with locking via DynamoDB, or Terraform Cloud) rather than sitting on one person's laptop. Losing it, or two people applying changes concurrently without locking, are the most common ways teams get burned early on.

The honest tradeoff

Terraform's cloud-agnostic design is also its main criticism: it's a generic abstraction over each provider's API, which means it sometimes lags behind a cloud's newest features (a brand-new AWS service might not have full Terraform provider support on day one) compared to a cloud-native tool that's always current with its own platform. For teams committed to a single cloud who want day-one access to every new feature, that's a real tradeoff. For most teams — especially anyone using more than one cloud or SaaS provider — the consistency wins.

Modules: Terraform's reuse mechanism

A Terraform module is a reusable, parameterized package of configuration — the same infrastructure pattern (a standard VPC layout, a standard web-app deployment shape) defined once and instantiated multiple times with different inputs, rather than copy-pasted per environment:

hcl
module "production_vpc" {
  source     = "./modules/vpc"
  cidr_block = "10.0.0.0/16"
  env        = "production"
}
 
module "staging_vpc" {
  source     = "./modules/vpc"
  cidr_block = "10.1.0.0/16"
  env        = "staging"
}

Both instantiations reuse the exact same underlying module code, differing only in the inputs passed — a fix or improvement to the module's internal logic (adding a missing tag, correcting a security group rule) propagates to every environment using it on the next apply, instead of needing to be hand-applied to each environment's separately copy-pasted configuration.

Terraform Cloud/Enterprise vs. self-managed state

Beyond a bare S3-plus-DynamoDB remote backend, HashiCorp's own Terraform Cloud (and the self-hosted Enterprise version) adds a managed layer on top: remote plan/apply execution (so apply runs in a consistent environment, not on whoever's laptop happens to run it), a UI for reviewing plans before approval, and built-in state locking without configuring DynamoDB manually. For a team already comfortable managing their own S3/DynamoDB backend and CI-driven applies, it's not strictly necessary — but for teams wanting a more guided, less self-assembled workflow around exactly the failure modes described above (state handling, concurrent applies, plan review), it's worth evaluating directly against a self-managed setup rather than assumed to be unnecessary overhead.

The same declarative discipline Terraform brings to raw infrastructure extends naturally into what runs on top of it — Kubernetes ConfigMaps and Secrets are the equivalent pattern one layer up, and a real-world 3-tier AWS deployment is exactly the kind of multi-resource setup where hand-clicking through a console stops being viable.

Common mistakes

Common mistakes
  • Making a manual change in the cloud console "just this once" to fix something urgently, then forgetting to reconcile it back into the Terraform configuration — the next plan either fights the manual change or silently reverts it.
  • Storing the state file locally (or committing it to git) instead of a remote backend with locking. A local state file can't safely be shared across a team, and committing it to git risks leaking sensitive values the state file often contains (like generated passwords).
  • Running terraform apply without reading the plan output first, especially in automation — a plan showing an unexpected "destroy" on a resource is exactly the kind of thing this workflow exists to catch before it happens, not after.
  • Writing one enormous Terraform configuration for an entire organization's infrastructure instead of splitting it into logical, independently-applied modules — a mistake in one part of a monolithic config can block or risk unrelated infrastructure during every single apply.
Advertisement

Frequently Asked Questions

Advertisement
DevFieldGuide
DevFieldGuide

Editorial Team

Practical tutorials and developer tools, written and maintained by the DevFieldGuide team.

Enjoyed this article?

Get the next one straight to your inbox, along with the best of what we publish each week.

Related Articles

More in DevOps

View all