Terraform Cheat Sheet
IaC commands and patterns for cloud interviews
Key Concepts
State file
Terraform's record of what it created. Maps your config to real infrastructure. The state file is the source of truth - if it drifts from reality, plan output will be wrong.
Never edit state manually. Use terraform state commands instead.
Idempotency
Running terraform apply multiple times on unchanged config produces no changes. Terraform computes a diff between desired state (config) and actual state (state file) each time.
Resource vs Data source
Resource: Terraform creates and manages it. Data source: reads an existing resource Terraform doesn't manage (e.g., look up an AMI ID, read a secret from Secrets Manager).
Provider
Plugin that talks to an API (AWS, GCP, Kubernetes). Defines which resource types are available. Pinned with version constraints to prevent breaking changes.
Module
A reusable group of resources with inputs (variables) and outputs. Like a function for infrastructure. Promotes DRY code and consistent patterns across environments.
Input variable vs Local value vs Output
Variable: external input (from tfvars or CLI). Local: computed value used internally. Output: value exposed to other modules or displayed after apply.
count vs for_each
count creates N identical resources indexed by number. for_each creates resources from a map or set, indexed by key. for_each is safer - removing an item doesn't shift indices.
lifecycle rules
prevent_destroy: blocks accidental deletion. create_before_destroy: provisions replacement before destroying original (blue/green). ignore_changes: prevents drift from updating a field.
Backend
Where state is stored. Default is local file. Remote backends (S3, Terraform Cloud) enable team collaboration, state locking (DynamoDB or S3 native), and encryption.
Workspaces
Isolated state files within the same backend. Used for environment separation (dev/stg/prd) within one codebase. Not recommended for large environment differences - use separate directories instead.
Implicit vs explicit dependency
Implicit: Terraform detects when resource A references resource B and waits automatically. Explicit: use depends_on when there is a dependency Terraform can not detect from references.
terraform plan -out
Saves the exact plan to a file. terraform apply planfile then applies exactly that plan - no recalculation, no surprises. Best practice before any risky apply.
Commands
Core Workflow
terraform init # download providers & modules terraform init -upgrade # upgrade provider versions terraform fmt # format all .tf files terraform fmt -check # exit 1 if formatting needed terraform fmt -recursive terraform validate # check syntax & config
terraform plan # preview changes terraform plan -out=tfplan # save plan to file terraform plan -var 'env=prd' terraform plan -target=aws_instance.web terraform apply # apply (prompts for confirm) terraform apply -auto-approve terraform apply tfplan # apply saved plan (no prompt) terraform apply -target=aws_instance.web
terraform destroy # destroy all terraform destroy -auto-approve terraform destroy -target=aws_instance.web
State Commands
terraform show # human-readable state terraform show tfplan # show saved plan terraform state list # list all resources terraform state show aws_instance.web # detail terraform state pull # download remote state terraform state push # upload local state
# Move resource to new address terraform state mv aws_instance.old aws_instance.new # Remove from state (does NOT destroy resource) terraform state rm aws_instance.web # Import existing resource into state terraform import aws_instance.web i-0abc123
# Refresh state from real infra terraform apply -refresh-only # Force-unlock state (if locked) terraform force-unlock <lock-id> # Taint (mark for replacement) terraform taint aws_instance.web # deprecated # Use: terraform apply -replace=aws_instance.web
Variables
# variables.tf declaration
variable "instance_type" {
type = string
description = "EC2 instance type"
default = "t3.small"
}
variable "allowed_cidrs" {
type = list(string)
}
variable "tags" {
type = map(string)
default = {}
}# terraform.tfvars
instance_type = "t3.medium"
allowed_cidrs = ["10.0.0.0/8"]
tags = {
Environment = "prd"
Team = "platform"
}
# Override on command line
terraform plan -var 'instance_type=t3.large'
# Use .tfvars file
terraform plan -var-file=prod.tfvars# Referencing variables
resource "aws_instance" "web" {
instance_type = var.instance_type
tags = var.tags
}
# Local values (computed, not input)
locals {
name_prefix = "${var.env}-${var.app}"
}
resource "aws_instance" "web" {
tags = { Name = local.name_prefix }
}Outputs & Data Sources
# outputs.tf
output "instance_ip" {
value = aws_instance.web.public_ip
description = "Public IP of web server"
}
output "db_endpoint" {
value = aws_db_instance.main.endpoint
sensitive = true # masked in CLI output
}
terraform output # show all outputs
terraform output instance_ip # show one# Data sources (read existing resources)
data "aws_ami" "amazon_linux" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["al2023-ami-*-x86_64"]
}
}
resource "aws_instance" "web" {
ami = data.aws_ami.amazon_linux.id
}Useful Patterns
# Count (create N copies)
resource "aws_instance" "web" {
count = 3
instance_type = "t3.small"
tags = { Name = "web-${count.index}" }
}
# For each (create from map/set)
resource "aws_s3_bucket" "buckets" {
for_each = toset(["dev", "stg", "prd"])
bucket = "myapp-${each.key}"
}# Lifecycle rules
resource "aws_db_instance" "main" {
lifecycle {
prevent_destroy = true # block destroy
create_before_destroy = true # blue/green
ignore_changes = [password]
}
}
# Dynamic blocks
dynamic "ingress" {
for_each = var.allowed_ports
content {
from_port = ingress.value
to_port = ingress.value
protocol = "tcp"
}
}Backends & Workspaces
# S3 backend (backend.tf)
terraform {
backend "s3" {
bucket = "my-tf-state"
key = "prd/terraform.tfstate"
region = "us-east-1"
encrypt = true
use_lockfile = true # S3 native locking
}
}# Workspaces
terraform workspace list
terraform workspace new dev
terraform workspace select prd
terraform workspace show # current
# Use workspace name in config
resource "aws_s3_bucket" "state" {
bucket = "myapp-${terraform.workspace}"
}# Remote state data source
data "terraform_remote_state" "vpc" {
backend = "s3"
config = {
bucket = "my-tf-state"
key = "shared/terraform.tfstate"
region = "us-east-1"
}
}
# Use outputs from remote state
module.vpc.id = data.terraform_remote_state.vpc.outputs.vpc_idModules
# Calling a module
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 5.0"
name = "my-vpc"
cidr = "10.0.0.0/16"
}
# Local module
module "app" {
source = "./modules/app"
env = var.env
}
# After adding a module
terraform init # always re-init firstInterview Tips
# Safe apply pattern terraform plan -out=changes.tfplan terraform show changes.tfplan # review terraform apply changes.tfplan # no surprises # Check for destroying or replacing terraform plan | grep -E "will be destroyed|must be replaced" # Back up state before risky ops terraform state pull > backup.json
# Key concepts to know: # - Terraform state = source of truth # - plan is idempotent (safe to run multiple times) # - destroy removes real infra, not just state # - -target is for emergencies, not routine use # - sensitive = true masks in output, NOT in state
acecloudinterviews.com - Free forever. No login required.