DevOps

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.

Marcus LeeJune 4, 20263 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.

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.

Advertisement
Marcus Lee
Marcus Lee

Cloud & DevOps Engineer

Marcus covers Kubernetes, cloud infrastructure, and CI/CD. He's spent a decade running production systems at scale.

Related Articles