Background

Terraform Guide

March 10, 202611 min read
TerraformIaCAWSAzureGCP

Terraform is a tool for describing infrastructure as text, in a file you can review, version and re-run, so that the thing running in your cloud account matches the thing written in your repository. That sentence is uncontroversial and almost useless. The interesting part is everything it hides: what happens between typing terraform apply and the resource existing, why the tool sometimes proposes to destroy something you only renamed, and what you do at 3am when the state file is locked by a pipeline run that died twenty minutes ago.

This article is about that part.

Who it's for

A working engineer who will have to operate the thing — not just write it once. You will have to defend the design in review, hand the repository to someone else, and get paged when it breaks. The article assumes you can use a terminal, have used at least one cloud console, and have never seriously used Terraform. It does not assume you know Go, HCL, or what a directed acyclic graph is.

If you already write Terraform daily, the pages worth your time are The Plan/Apply Lifecycle, The Dependency Graph, Meta-Arguments and Import & Refactoring.

The promise

Plain-English intuition first, then the precise mechanics underneath, then the trade-offs nobody advertises.

Most Terraform material picks one of those three. Tutorials give you the intuition and a working snippet, then stop before anything is explained. Reference documentation gives you the mechanics with no reason to care. Almost nobody writes down the third thing — that provisioner is a supported feature and is nearly always the wrong answer, that -target is a debugging tool masquerading as a workflow, that workspaces solve a problem most teams don't have while creating one they do.

Two more commitments:

  • Every term is defined the first time it appears. Including the ones that seem obvious. "Drift", "state", "resource address", "backend" and "provider" all mean something specific and none of them mean what a newcomer guesses.
  • Every runnable example exists in AWS, Azure and GCP. Terraform's pitch is provider-agnostic syntax; an article that only ever shows aws_* resources quietly undercuts its own argument. The running example is object storage — a bucket — for the whole article, so you are never learning a new cloud service and a new Terraform concept in the same paragraph. Where the three clouds do the same thing, you get one block and a note; where they genuinely diverge, you get all three side by side.

Read it in order

This matters more here than in the AWS and Azure articles, which are catalogues you can dip into by service. Terraform isn't a catalogue. It is one tool with about a dozen deep ideas, and the ideas depend on each other in a specific way.

The six stages are ordered by that dependency. Each answers the question what can you not correctly do without this? — so a topic appears as early as it can be understood, and as late as it must be to be understood correctly. Three consequences are worth flagging, because they're places where this article deliberately disagrees with how Terraform is usually taught:

  • State is split in two. Early on you get only "there is a file that maps your configuration to real objects, and you don't hand-edit it" — the minimum needed to run apply honestly. Backends, locking and state mv wait until State & Backends, because state is only comprehensible once you can read a plan.
  • count and for_each come after the dependency graph, not with the rest of the syntax. Taught as syntax, for_each looks like a loop and you write count = length(var.list) forever. Taught after the graph, "the for_each key becomes the resource address" explains itself — and so does the most common self-inflicted production disaster in Terraform.
  • Import and refactoring is a mid-article survival skill, not an advanced flourish. Every real job is brownfield.

If you're impatient: Stages 0–2 are the point at which you can be trusted with a real repository under supervision. Stages 3–5 are the difference between writing Terraform and owning it.

The shape of every page

Every topic page has the same sections in the same order, so once you've read three pages you know where to scroll in the fourth. Small topics drop sections rather than padding them; surviving sections never reorder.

Section The question it answers
What & Why What is it, what bad practice did it replace, and when is it the wrong tool?
Core Concepts Every noun you'll meet — plain-English gloss, then precise definition
How It Works What Terraform actually does: what happens at plan time, what gets written where, what forces replacement, how it fails
Getting Started The smallest throwaway config that proves the behaviour. Config → commands → output, and the output is the lesson
In Practice The version you'd ship: typed variables, pinned versions, what a reviewer should look for, blast radius, rollback
Ecosystem The 3–5 things it's used with — other features, provider quirks, external tooling
Production Security · Blast radius · Scale · Team workflow · Reliability
Interview Questions Fifteen, in three tiers, with answers — including at least one "how does this differ across AWS, Azure and GCP?"

Each page closes with a Commands & Gotchas block: the handful of commands and expressions you'd actually reach for on that topic, plus the behaviours worth memorising.

Contents

Legend: ✅ Available · 🚧 In progress · 📋 Planned

Stage 0 — Orientation

You can provision and destroy something real, and explain every file that appeared. · ~1 week

# Topic What it covers Status
1 Why IaC Exists Click-ops and why it fails; drift as the real problem; declarative versus imperative; Terraform against CloudFormation, Bicep, Pulumi, Ansible, Crossplane 🚧
2 The Core Workflow initvalidateplanapplydestroy; what each command reads and writes; which are safe unattended 🚧
3 Anatomy of a Project The .tf split as convention; .terraform/; the lock file; the state file; what belongs in git and what absolutely does not 🚧

Stage 1 — The Language

You can write a multi-resource configuration from scratch without copying an example. · ~3 weeks

# Topic What it covers Status
1 HCL & the Type System Blocks, arguments, attributes; primitives; list vs set vs map vs object vs tuple; conversion rules; why a .tf file is evaluated, not executed 🚧
2 Providers & the Registry Providers as plugins; required_providers and the ~> constraint; the lock file; alias and multi-account; the auth chain for each cloud 🚧
3 Resources & References The resource block; arguments versus attributes; implicit dependencies; (known after apply); resource addresses; data sources and when they're the wrong reach 🚧
4 Variables, Locals & Outputs Typed inputs with validation and sensitive; the precedence order that trips everyone; locals versus variables; what outputs are really for 🚧
5 Expressions & Functions Conditionals; for expressions; splat; dynamic blocks and when they're a mistake; templatefile; the functions worth memorising 🚧

Stage 2 — The Machinery

You can look at a plan and say what will happen and why, before running it. · ~2 weeks

# Topic What it covers Status
1 The Plan/Apply Lifecycle Parse → resolve → refresh → graph → diff → render; plan files; reading + - ~ -/+ <=; what forces replacement; why unknown values propagate 🚧
2 The Dependency Graph What creates an edge; what parallelises and what serialises; -parallelism; walking the graph to explain an ordering surprise 🚧
3 Meta-Arguments count versus for_each and the addressing consequence; depends_on as a code smell; the four lifecycle settings; per-resource provider 🚧

Stage 3 — Structuring Real Code

A second engineer can clone your repo and apply to a different environment without asking you anything. · ~2 weeks

# Topic What it covers Status
1 Modules Root versus child; a module as an interface; sources and pinning; composition versus nesting; when a module is premature 📋
2 Repo & Environment Structure Directory-per-environment versus workspaces versus Terragrunt; .tfvars layering; where to put the state seams; the layout to pick and the one to reject 📋
3 State & Backends Backend configuration; locking and contention; the bootstrapping chicken-and-egg; state list/show/mv/rm; why a state file is a security problem 📋

Stage 4 — Working on a Team

A change reaches production through a pipeline with a review and an approval, and someone other than you can roll it back. · ~3 weeks

# Topic What it covers Status
1 Import & Refactoring import blocks and config generation; moved and removed; renaming without destroying; adopting a brownfield estate 📋
2 Testing & Validation fmt and validate; tflint; checkov/tfsec; check blocks; terraform test; Terratest and when the cost is justified 📋
3 CI/CD & Automation Plan on pull request; apply on merge; OIDC instead of long-lived keys; approval gates; -detailed-exitcode; Atlantis as the alternative model 📋
4 Governance & Policy as Code Sentinel and OPA/Conftest; HCP Terraform workspaces and run tasks; private module registries; cost gates 📋

Stage 5 — Production & Depth

You can be on call for a Terraform-managed estate. · ~3 weeks

# Topic What it covers Status
1 Secrets & Sensitive Data Secrets in state and plan output; the real limits of sensitive = true; ephemeral values and resources; the Vault provider; who can read the bucket 📋
2 Scale & Performance Behaviour at thousands of resources; refresh cost; -parallelism; provider rate limits; when the answer is "split the state" 📋
3 Failure & Recovery Partial applies; force-unlock and when it's safe; lost or corrupted state; restoring from a versioned backend; the drill you should have rehearsed 📋
4 Drift & Reconciliation Detecting console changes; ignore_changes as concession versus surrender; continuous drift detection; what to do when reality is right 📋
5 Extending & the Ecosystem The plugin protocol; provider-defined functions; writing a provider; Stacks; CDKTF; Terragrunt; OpenTofu; migrating from CloudFormation or Bicep 📋

Reference

Page What it covers Status
Glossary & Cheatsheet Every term defined anywhere in the article, alphabetised and linked back; the CLI surface grouped by workflow; the expression forms worth knowing; the consolidated gotchas table 📋

Versions, and the OpenTofu question

Written against Terraform 1.x. Where a feature has a minimum version, the page says so — import blocks and check blocks arrived in 1.5, terraform test in 1.6, removed blocks in 1.7, provider-defined functions in 1.8, ephemeral values in 1.10. If an example doesn't work for you, terraform version is the first thing to check.

In August 2023, HashiCorp changed Terraform's licence from the Mozilla Public License to the Business Source License, which restricts use in competing commercial products. The Linux Foundation forked the last MPL version as OpenTofu, which remains open source and is broadly a drop-in replacement: same HCL, same providers, same state format, tofu instead of terraform on the command line. The two have since diverged somewhat in features, and OpenTofu has shipped things Terraform hasn't (state encryption, for one).

For anyone learning, this changes almost nothing — everything in this article applies to both unless a page says otherwise, in which case it says so in one line rather than forking into two versions. For anyone choosing for an organisation, it's a licensing and roadmap question rather than a technical one, and it's worth reading the current licence text rather than a summary written at some point in the past.

The applied counterparts, service by service: AWS · Azure