Terraform 80/20 — Commands, Concepts, Context¶
The Core Workflow¶
Every Terraform task follows this exact sequence. You will use these commands on every single thing you do.
# 1 - Initialise a working directory
# Downloads providers and modules defined in your config.
# Run this first, always. Nothing works without it.
terraform init
# 2 - Preview what Terraform will do
# Shows what will be created, changed, or destroyed.
# Nothing is applied. Read this carefully before applying.
terraform plan
# 3 - Apply the changes
# Actually creates/modifies/destroys infrastructure.
# Asks for confirmation unless you pass -auto-approve.
terraform apply
# 4 - Destroy all infrastructure managed by this config
# Tears everything down. Useful for labs/cleanup.
# Same as apply but in reverse.
terraform destroy
Inspecting State¶
Terraform tracks what it created in a state file (terraform.tfstate). State is the source of truth — it's how Terraform knows what exists. These commands let you inspect and manage it.
# 5 - List all resources Terraform is tracking
terraform state list
# 6 - Show details of a specific tracked resource
# Use after state list to get the resource address
terraform state show <resource_address>
# 7 - Show current state of all resources (full output)
terraform show
# 8 - Remove a resource from state WITHOUT destroying it
# Use when you want Terraform to forget about something
# without actually deleting it from the infrastructure
terraform state rm <resource_address>
# 9 - Import existing infrastructure into state
# Use when something already exists and you want
# Terraform to start managing it
terraform import <resource_address> <real_world_id>
Validation and Formatting¶
Before applying, always validate and format. Catches syntax errors early. Keeps code readable.
# 10 - Check config files for syntax errors
# Does not check against provider APIs — just HCL syntax
terraform validate
# 11 - Auto-format .tf files to canonical style
# Run this before committing code
terraform fmt
# 12 - Recursive format (all subdirectories)
terraform fmt -recursive
Variables and Outputs¶
Variables let you reuse configs. Outputs expose values after apply (e.g. IP addresses, IDs). You'll use both constantly.
# 13 - Pass a variable value on the command line
terraform apply -var="instance_type=t2.micro"
# 14 - Pass variables from a file
# .tfvars files hold key=value pairs
terraform apply -var-file="prod.tfvars"
# 15 - Show all output values after apply
terraform output
# 16 - Show a specific output value
terraform output <output_name>
Workspaces¶
Workspaces let you manage multiple environments (dev, staging, prod) from the same config. Each workspace has its own state file. Default workspace is called "default".
# 17 - List all workspaces
terraform workspace list
# 18 - Create a new workspace
terraform workspace new <name>
# 19 - Switch to a workspace
terraform workspace select <name>
# 20 - Show current workspace
terraform workspace show
Providers and Modules¶
Providers are plugins that talk to APIs (AWS, GCP, Azure). Modules are reusable chunks of config.
# 21 - Show required providers and their versions
terraform providers
# 22 - Upgrade providers to latest allowed version
terraform init -upgrade
# 23 - Download modules defined in config
# Actually just terraform init — modules are fetched on init
terraform get
Targeting and Partial Applies¶
Sometimes you only want to apply or destroy one specific resource. Use -target. Avoid this in production — it creates state drift.
# 24 - Apply only a specific resource
terraform apply -target=<resource_address>
# 25 - Destroy only a specific resource
terraform destroy -target=<resource_address>
Useful Flags¶
# Skip the yes/no confirmation prompt
terraform apply -auto-approve
terraform destroy -auto-approve
# Save a plan to a file, then apply exactly that plan
terraform plan -out=myplan.tfplan
terraform apply myplan.tfplan
# See verbose debug output (use when something is broken)
TF_LOG=DEBUG terraform apply
Key Concepts (no terminal needed)¶
HCL Blocks — the 5 you must know¶
# Provider — tells Terraform which API to talk to
provider "aws" {
region = "us-east-1"
}
# Resource — the thing you're creating
resource "aws_instance" "web" {
ami = "ami-12345"
instance_type = "t2.micro"
}
# Variable — input value, makes config reusable
variable "instance_type" {
type = string
default = "t2.micro"
}
# Output — expose a value after apply
output "instance_ip" {
value = aws_instance.web.public_ip
}
# Data source — READ existing infrastructure, don't create it
data "aws_ami" "latest" {
most_recent = true
owners = ["amazon"]
}
State — what it is and why it matters¶
- Terraform stores what it created in
terraform.tfstate - Every apply reads state to know what already exists
- State is the diff between "what the code says" and "what's real"
- If state is lost or corrupted, Terraform doesn't know what it owns
- Never edit state manually — use
terraform statecommands - In teams, state is stored remotely (S3 + DynamoDB for AWS) so multiple people don't conflict
The Dependency Graph¶
- Terraform figures out the order to create resources automatically
- If resource B references resource A, Terraform creates A first
- You don't specify order — it's inferred from references
terraform graphoutputs a visual dependency graph (DOT format)
Modules¶
- A module is just a folder with .tf files
- Every Terraform config is technically a module (the root module)
- You call child modules to reuse config across environments
- Input = variables, Output = outputs
- Public modules available at registry.terraform.io
Remote Backend (S3 example)¶
terraform {
backend "s3" {
bucket = "my-tf-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "tf-state-lock" # prevents concurrent applies
}
}
Lifecycle Rules¶
resource "aws_instance" "web" {
ami = "ami-12345"
instance_type = "t2.micro"
lifecycle {
create_before_destroy = true # create replacement before deleting old
prevent_destroy = true # block destroy — good for databases
ignore_changes = [tags] # don't update resource if only tags changed
}
}
Exam Cheat Reference¶
| Concept | What to remember |
|---|---|
| init | downloads providers + modules, run first always |
| plan | preview only, nothing changes |
| apply | makes real changes, asks confirmation |
| state | source of truth, never edit manually |
| tfstate | local file storing state, don't commit to git |
| workspace | separate state per environment, same config |
| module | reusable folder of .tf files |
| provider | plugin that talks to an API (AWS, GCP etc) |
| data source | reads existing infra, doesn't create anything |
| remote backend | stores state in S3/GCS for team use |
| -target | apply/destroy one resource only, avoid in prod |
| prevent_destroy | lifecycle rule to block accidental deletion |
| terraform.tfvars | auto-loaded variable file, don't commit secrets |