Terraform – What It Is and Why It Exists

July 10, 20267 min readUpdated 8/24/2026

You need a server, a database and a load balancer. You open the AWS console, click through four wizards, and twenty minutes later it works. Then someone asks you to build the same thing again for staging, and you cannot — because you do not remember which of the forty checkboxes you ticked.

Terraform is the answer to that. You write down what the infrastructure should be, in a file, and a tool makes reality match. The file goes in git, so "what changed?" and "who changed it?" become questions with answers.

What infrastructure as code actually buys you

Not "automation" — you can automate with a shell script. Four specific things:

It is repeatable. The same file produces the same infrastructure in staging and production. The difference between them is a variable, not a memory.

It is reviewable. "Open port 22 to the world" is a line in a pull request that a colleague can object to, rather than something that happened in a console at 11pm.

It is reversible. The previous version of the file is in git, and applying it puts things back.

It tells you what it is about to do. This is the part people underestimate. Terraform shows you the diff — create these six, change this one, destroy that database — and waits. Most of the value is in reading that output and saying no.

The idea, in one loop

Terraform holds three things and reconciles them:

your .tf files      what you want
terraform state     what Terraform believes it built
the real AWS API    what is actually there

plan  = compare all three, print the difference
apply = make the difference go away

That is the whole tool. Everything else — modules, variables, backends — is about keeping that loop manageable as the amount of infrastructure grows.

It matters that Terraform is declarative. You do not write "create a VPC". You write "a VPC exists, with this CIDR", and Terraform works out whether that means creating one, changing one, or doing nothing. Run it twice and the second run does nothing, which is the property a shell script full of aws ec2 create-vpc does not have.

What it looks like

Here is a real resource from the stack this track deploys later. You do not need to follow the details yet — just the shape:

resource "aws_ecs_cluster" "this" {
  name = "pizza-tf"

  tags = {
    Project = "terraform-tutorial"
  }
}

A block type (resource), a resource type (aws_ecs_cluster), a name you choose (this), and arguments. Roughly every line of Terraform you will ever write is that shape.

Where Terraform sits next to the alternatives

These get compared constantly and the comparisons are usually unfair. The honest version:

CloudFormation is AWS's own, in YAML or JSON. It is free, deeply integrated, and AWS supports new services there first. It is also AWS-only, and its error messages and rollback behaviour are widely disliked. If you are certain you will never touch a second cloud or a non-cloud provider, it is a reasonable choice.

AWS CDK is CloudFormation with TypeScript or Python in front of it. You get loops, types and an IDE. You also get a compile step, and the thing that actually deploys is still CloudFormation — so you debug generated templates when it goes wrong.

Pulumi is the same idea as CDK but multi-cloud and not built on CloudFormation. Genuinely good. Much smaller ecosystem, and a real programming language means real programs, which means infrastructure code with bugs in its control flow.

Ansible is a different category and the comparison is a category error. Terraform provisions — it creates the server. Ansible configures — it installs packages on a server that exists. They are often used together. Ansible can create AWS resources, but it has no plan step and no state, so it cannot tell you what it is about to change.

Terraform's actual advantage is the provider ecosystem: AWS, GCP, Azure, Cloudflare, Datadog, GitHub, Kubernetes and several thousand more, all driven by the same language and the same plan/apply loop. Most real systems are not one vendor.

The licence changed, and there is a fork

You need to know this because every tutorial written before August 2023 gets it wrong by omission.

On 2023-08-10 HashiCorp moved Terraform from the MPL 2.0 open source licence to the Business Source License. In practice the BSL restricts using Terraform to build a competing commercial product; for the overwhelming majority of users — companies managing their own infrastructure — nothing changed and it remains free to use.

The reaction was a fork of the last MPL commit, now a Linux Foundation project called OpenTofu. It is a drop-in replacement for most usage: same HCL, same providers, tofu instead of terraform.

This track uses Terraform, and everything in it applies to OpenTofu with the binary renamed. If your employer has a policy about the BSL, OpenTofu is the answer; otherwise the choice rarely matters day to day. That is the whole of the politics, and it will not come up again.

The versions this is written against

Infrastructure content rots faster than almost anything else — arguments get renamed, resources move, defaults change. So: exact versions, read off the machine that wrote this, not copied from a docs page.

terraform    1.15.9
aws provider 6.61.0        (hashicorp/aws)
aws cli      2.32.24
region       us-west-2

Two things in particular are worth knowing are recent, because the internet is full of advice that predates them:

  • State locking no longer needs DynamoDB. Terraform 1.10 added native locking on S3, and 1.11 made it the default and deprecated the dynamodb_table argument. Every older tutorial tells you to create a lock table. Lesson 8 explains what to do instead.
  • The AWS provider is on major version 6. Version 4 and 5 examples frequently fail to plan, most visibly around S3 bucket configuration, which was split from one resource into about a dozen.

The application this deploys

The AWS lessons are not abstract. They deploy a real Spring Boot application — a pizza ordering API with MySQL, Liquibase migrations, JWT auth and Stripe payments — to ECS Fargate behind an application load balancer, with a GitHub Actions pipeline in front of it.

Everything quoted in those lessons came from a stack that was actually applied to a real AWS account, checked through the load balancer, and then destroyed. Where something broke, the lesson says what broke and what the error looked like, because the errors are the part worth having read before you meet them.

What you need before lesson 2

  • An AWS account you are allowed to create things in.
  • The AWS CLI, configured — aws sts get-caller-identity should return your account.
  • A willingness to spend a few dollars. The AWS lessons build a load balancer, a NAT gateway and an RDS instance, which together cost about $0.13/hour and are outside the free tier. Every lesson that creates something says what it costs and ends by destroying it.

The track

Sixteen lessons, in reading order. The first eleven are the language and the tool; the last five are a real deployment.

Foundations

  1. Terraform – What It Is and Why It Exists (you are here)
  2. Install It and Run Your First Apply — the initplanapplydestroy loop
  3. HCL Syntax You Will Actually Use — blocks, types, expressions, functions
  4. Providers, Versions and the Lock File — pinning, and why the lock file is committed
  5. Resources and the State File — what state is, and the commands for when it disagrees with reality

Making it reusable

  1. Variables, Locals and Outputs — typed inputs, validation, and what sensitive does not do
  2. Data Sources — reading infrastructure you did not create
  3. Remote State and Locking on S3 — and why the DynamoDB table everyone tells you to create is obsolete
  4. count, for_each and Dynamic Blocks — and the reason count will destroy half your resources
  5. Writing and Using Modules — including when not to
  6. Dev, Staging and Prod Without Copy-Paste — why workspaces are a trap for production

A real deployment on AWS

  1. Building the Network and Database — VPC, subnets, security groups, RDS, and keeping the password out of the state file
  2. Deploying a Spring Boot API to ECS Fargate — ECR, task definitions, the load balancer, and the health check that has to be exactly right
  3. A CI/CD Pipeline in GitHub Actions — plan on the PR, apply on merge, and no stored AWS keys
  4. Running It in Production — drift, secrets, prevent_destroy, and reading a plan properly
  5. Interview Questions

Start with lesson 2, which installs the thing and creates something real in about ten minutes.