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).
# 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:
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:
terraform plan # shows what WOULD change, without changing anything
terraform apply # actually makes the changeterraform 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.