Terraform Basics
Write the desired world; let the engine converge it
Terraform is a declarative IaC engine: HCL describes resources, the provider talks to the cloud, and plan/apply turn intent into reality. Learn the hair gets — init, plan, apply, destroy — plus core constructs: resources, data sources, variables, outputs.
What you will learn
- Run init/plan/apply/destroy on a small stack
- Read and write HCL resource blocks
- Use variables, outputs and the provider registry
HCL resource blocks declare resources; providers (aws, azurerm, google) translate those declarations into API calls. `terraform plan` diffs desired-vs-current; `apply` executes the diff; `destroy` tears the stack down. State records what exists.
What is this?
Core files: main.tf (resources), variables.tf (typed inputs), outputs.tf (interfaces), terraform.tfstate (state). Run-order: init (download providers/modules + lock), validate/plan (graph + diff), apply (changes), destroy (reverse). Resource syntax: resource "provider_type" "name" { argument = value }. Data sources read existing infra. Ternary/expressions, for_each/count, depends_on. Provider registry + required_providers. CLI env: TF_VAR_*, -var-file prod.tfvars.
Why do you need it?
- Infra as code you can review, version, and revert — the heart of DevOps.
- Plan previews every mutation before anything happens.
- Multi-cloud and multi-provider from one language and one workflow.
- Destroy = reversible teardown; ephemeral per-PR environments become cheap.
Mental model
Giving a GPS your route's endpoints and letting it plan the exact turns
Terraform plan/apply
You state destinations (resources) and preferences (variables); the GPS builds a route (plan) you approve; then you drive (apply). You never yell 'turn left at the third street' — that's imperative's job.
How it works
- init resolves providers/modules and creates the backend connection + lock file.
- plan builds a dependency graph and a diff of add/change/destroy.
- apply executes planned actions in dependency order, writing state.
- State stores attribute values; next plan merges them with live API state.
- destroy reverses the graph and empties state.
Core Terraform loop.
Examples
The smallest useful stack
terraform { required_providers { random = { source = "hashicorp/random" } }}variable "env" { type = string }resource "random_pet" "this" { length = 2 }output "id" { value = "${var.env}-${random_pet.this.id}" }Vars in, output out, provider wired — the full cycle fits in ten lines.
In production
- Networking + IAM + app tiers codified per environment with remote state.
- Zero downtime infra changes behind feature-flagged PRs that run plan in CI.
- Ephemeral preview environments: applied on PR open, destroyed on merge.
Best practices
- Always plan first, review the diff, then apply — automation gates apply.
- Pin provider versions in required_providers; use the lock file.
- Keep state remote and locked (see State & Backends).
- Small, reviewable changes; never apply opaque 'big bang' diffs.
- Use outputs as the only interface to read post-apply values.
Common mistakes
- terraform apply as the first thing you run (no plan, no review).
- Forgetting -var-file so a different env gets prod values.
- Local state in a team repo → clobbered and no audit.
- Ignoring provider upgrade warnings until a silent force-new cascade appears.
Debugging tips
- Plan shows unwanted delete → check for renamed resource or state identity mismatch.
- Provider auth error → creds/region mismatch, or init missing the provider.
- Validate passes, apply fails → API constraints (name uniqueness, IAM) beat HCL rules.
- Re-run plan after a failed apply — it reveals exactly what's wedged in state.
Interview checkpoint
Hands-on lab
- Initialize with a provider
- Provision a small resource and read outputs
- Destroy cleanly and verify state is empty
Run the Core Loop on a Real Provider
40 min · beginner
Quick quiz
Which command downloads providers/modules?
Terraform state's job is to remember what it created so plans can diff accurately against reality.