Installation & Setup
Install Terraform
bash
1# macOS (Homebrew)2brew tap hashicorp/tap3brew install hashicorp/tap/terraform4
5# Linux (apt — Debian/Ubuntu)6wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg7echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list8sudo apt update && sudo apt install terraform9
10# Linux (yum — RHEL/Fedora)11sudo yum install -y yum-utils12sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo13sudo yum install terraform14
15# Verify installation16terraform -versionEnable Autocomplete
bash
1# Install autocomplete (bash/zsh)2terraform -install-autocomplete3
4# Restart shell or source config5source ~/.bashrc # Bash6source ~/.zshrc # ZshUseful Aliases
bash
1alias tf=terraform2alias tfi='terraform init'3alias tfp='terraform plan'4alias tfa='terraform apply'5alias tfd='terraform destroy'6alias tff='terraform fmt'7alias tfv='terraform validate'8alias tfs='terraform state list'9alias tfw='terraform workspace list'Important Paths & Config Files
Project Structure
bash
1project/2├── main.tf # Primary resource definitions3├── variables.tf # Input variable declarations4├── outputs.tf # Output value definitions5├── providers.tf # Provider configuration6├── terraform.tfvars # Variable values (auto-loaded)7├── terraform.tfvars.json # Variable values in JSON (auto-loaded)8├── *.auto.tfvars # Additional auto-loaded variable files9├── backend.tf # Backend configuration (state storage)10├── versions.tf # Required provider/terraform versions11├── locals.tf # Local values12├── data.tf # Data source definitions13└── modules/ # Local module directory14 └── vpc/15 ├── main.tf16 ├── variables.tf17 └── outputs.tfGenerated Files & Directories
bash
1.terraform/ # Working directory (providers, modules, plugins)2.terraform/providers/ # Downloaded provider plugins3.terraform/modules/ # Downloaded modules4.terraform.lock.hcl # Dependency lock file (commit to VCS)5terraform.tfstate # Local state file (DO NOT commit if using remote backend)6terraform.tfstate.backup # Previous state backup7crash.log # Crash log (generated on Terraform panic)Environment Variables
bash
1TF_LOG=TRACE # Enable debug logging (TRACE, DEBUG, INFO, WARN, ERROR)2TF_LOG_PATH=./terraform.log # Write logs to file3TF_VAR_region="us-west-2" # Set input variable via env var (TF_VAR_<name>)4TF_CLI_ARGS="-input=false" # Default CLI arguments5TF_CLI_ARGS_plan="-out=tfplan" # Default arguments for specific subcommand6TF_DATA_DIR=.terraform # Set working directory location7TF_PLUGIN_CACHE_DIR="$HOME/.terraform.d/plugin-cache" # Plugin cache directory8TF_IN_AUTOMATION=true # Adjust output for CI/CD environments9TF_INPUT=0 # Disable interactive promptsCore Workflow
Initialize Project
bash
1terraform init # Initialize working directory, download providers2terraform init -upgrade # Upgrade providers/modules to latest allowed versions3terraform init -reconfigure # Reconfigure backend, ignoring saved config4terraform init -migrate-state # Migrate state to new backend5terraform init -backend=false # Skip backend initialization6terraform init -backend-config="bucket=my-bucket" # Partial backend config7terraform init -backend-config=backend.hcl # Backend config from file8terraform init -get=false # Skip module downloadsFormat & Validate
bash
1terraform fmt # Auto-format .tf files to canonical style2terraform fmt -check # Check formatting (return non-zero if changes needed)3terraform fmt -diff # Show formatting differences4terraform fmt -recursive # Format files in subdirectories too5
6terraform validate # Check configuration syntax & internal consistency7terraform validate -json # Output validation results as JSONPlan Changes
bash
1terraform plan # Preview changes without applying2terraform plan -out=tfplan # Save plan to file for later apply3terraform plan -var="region=us-west-2" # Set variable inline4terraform plan -var-file="prod.tfvars" # Load variables from file5terraform plan -target=aws_instance.web # Plan only specific resource6terraform plan -destroy # Preview what would be destroyed7terraform plan -refresh-only # Only refresh state, no changes8terraform plan -replace=aws_instance.web # Plan replacement of specific resource9terraform plan -detailed-exitcode # Exit 0=no changes, 1=error, 2=changes present10terraform plan -parallelism=20 # Limit concurrent operations (default: 10)11terraform plan -compact-warnings # Show warnings in compact formatApply Changes
bash
1terraform apply # Apply changes (interactive approval)2terraform apply -auto-approve # Apply without confirmation prompt3terraform apply tfplan # Apply a saved plan file4terraform apply -var="env=production" # Set variable inline5terraform apply -var-file="prod.tfvars" # Load variables from file6terraform apply -target=aws_instance.web # Apply only specific resource7terraform apply -replace=aws_instance.web # Force replacement of a resource8terraform apply -parallelism=20 # Limit concurrent operations9terraform apply -refresh=false # Skip state refresh before apply10terraform apply -lock=false # Don't hold state lock during applyDestroy Infrastructure
bash
1terraform destroy # Destroy all managed resources2terraform destroy -auto-approve # Destroy without confirmation3terraform destroy -target=aws_instance.web # Destroy only specific resource4terraform plan -destroy # Preview what will be destroyed5terraform plan -destroy -out=destroy.tfplan # Save destroy plan6terraform apply destroy.tfplan # Apply saved destroy planState Management
Inspect State
bash
1terraform show # Show current state in human-readable format2terraform show tfplan # Show saved plan in human-readable format3terraform show -json # Output state as JSON4terraform show -json tfplan # Output saved plan as JSON5
6terraform state list # List all resources in state7terraform state list module.vpc # List resources in a module8terraform state show aws_instance.web # Show details of a specific resourceModify State
bash
1terraform state mv aws_instance.old aws_instance.new # Rename resource in state2terraform state mv aws_instance.web module.web.aws_instance.main # Move resource into module3terraform state mv -state-out=other.tfstate aws_instance.web aws_instance.web # Move to another state4
5terraform state rm aws_instance.web # Remove resource from state (does NOT destroy)6terraform state rm module.vpc # Remove entire module from state7
8terraform state replace-provider hashicorp/aws registry.example.com/aws # Replace provider in statePull & Push State
bash
1terraform state pull # Download remote state to stdout2terraform state pull > backup.tfstate # Backup remote state to file3terraform state push terraform.tfstate # Upload local state to remote backend4terraform state push -force state.tfstate # Force push (use with extreme caution)Import Existing Resources
bash
1terraform import aws_instance.web i-0abc123def456 # Import existing resource into state2terraform import module.vpc.aws_vpc.main vpc-0123456789 # Import into a module3terraform import -var-file="prod.tfvars" aws_instance.web i-0abc123 # Import with variables4
5# Import block (Terraform 1.5+ — declarative, recommended)6# Add to .tf file:7# import {8# to = aws_instance.web9# id = "i-0abc123def456"10# }11# Then run: terraform plan -generate-config-out=generated.tfState Locking
bash
1terraform force-unlock LOCK_ID # Manually unlock state (use with caution)2terraform force-unlock -force LOCK_ID # Force unlock without confirmation3terraform plan -lock=false # Run without state locking4terraform apply -lock-timeout=5m # Wait up to 5 minutes for lockWorkspaces
Manage Workspaces
bash
1terraform workspace list # List all workspaces2terraform workspace show # Show current workspace name3terraform workspace new staging # Create and switch to new workspace4terraform workspace select production # Switch to existing workspace5terraform workspace delete staging # Delete a workspace (must be empty)6terraform workspace delete -force staging # Force delete workspace even with resourcesWorkspace Usage in Config
hcl
1# Reference current workspace in configuration2resource "aws_instance" "web" {3 tags = {4 Environment = terraform.workspace5 }6}7
8# Conditional logic based on workspace9locals {10 instance_type = terraform.workspace == "production" ? "m5.large" : "t3.micro"11}Outputs & Expressions
View Outputs
bash
1terraform output # Show all outputs2terraform output -json # Show all outputs as JSON3terraform output instance_ip # Show specific output4terraform output -raw instance_ip # Show raw value (no quotes, useful for scripting)Interactive Console
bash
1terraform console # Launch interactive expression console2
3# Example session:4# > var.region5# "us-west-2"6# > aws_instance.web.public_ip7# "54.183.22.100"8# > length(var.availability_zones)9# 310# > cidrsubnet("10.0.0.0/16", 8, 1)11# "10.0.1.0/24"12# > exitProviders
Manage Providers
bash
1terraform providers # Show providers required by configuration2terraform providers mirror /path/to/dir # Mirror providers to local directory3terraform providers lock # Update dependency lock file4terraform providers lock -platform=linux_amd64 -platform=darwin_amd64 # Lock for specific platforms5terraform providers schema -json # Output provider schemas as JSON6
7terraform version # Show Terraform and provider versionsProvider Configuration
hcl
1# Require specific provider versions2terraform {3 required_version = ">= 1.5.0"4
5 required_providers {6 aws = {7 source = "hashicorp/aws"8 version = "~> 5.0"9 }10 azurerm = {11 source = "hashicorp/azurerm"12 version = ">= 3.0, < 4.0"13 }14 }15}16
17provider "aws" {18 region = var.region19 profile = var.aws_profile20}Backend Configuration
Local Backend (Default)
hcl
1terraform {2 backend "local" {3 path = "terraform.tfstate"4 }5}S3 Backend (AWS)
hcl
1terraform {2 backend "s3" {3 bucket = "my-terraform-state"4 key = "production/terraform.tfstate"5 region = "us-west-2"6 encrypt = true7 dynamodb_table = "terraform-locks"8 }9}Consul Backend
hcl
1terraform {2 backend "consul" {3 address = "consul.example.com:8500"4 scheme = "https"5 path = "terraform/production"6 }7}Azure Blob Backend
hcl
1terraform {2 backend "azurerm" {3 resource_group_name = "tfstate-rg"4 storage_account_name = "tfstate12345"5 container_name = "tfstate"6 key = "production.terraform.tfstate"7 }8}GCS Backend (Google Cloud)
hcl
1terraform {2 backend "gcs" {3 bucket = "my-terraform-state"4 prefix = "terraform/state"5 }6}Debugging & Troubleshooting
Enable Logging
bash
1# Set log level (TRACE, DEBUG, INFO, WARN, ERROR)2export TF_LOG=DEBUG3terraform plan4
5# Write logs to file6export TF_LOG=TRACE7export TF_LOG_PATH=./terraform.log8terraform apply9
10# Disable logging11unset TF_LOG12unset TF_LOG_PATHInspect & Debug
bash
1terraform graph # Generate visual dependency graph (DOT format)2terraform graph | dot -Tpng > graph.png # Render graph as PNG (requires graphviz)3
4terraform state list # List all tracked resources5terraform state show aws_instance.web # Show resource details from state6
7terraform refresh # Reconcile state with real infrastructure (deprecated, use plan -refresh-only)8terraform plan -refresh-only # Detect drift without making changesCommon Issues
bash
1# State locked?2terraform force-unlock LOCK_ID3
4# Provider version conflict?5terraform init -upgrade6
7# Corrupted state?8terraform state pull > backup.tfstate # Backup first9terraform state push fixed.tfstate # Push corrected state10
11# Plugin cache issues?12rm -rf .terraform/ # Clear providers/modules13terraform init # Re-download everything14
15# Crash log generated?16cat crash.log # Review crash detailsResource Targeting & Lifecycle
Target Specific Resources
bash
1terraform plan -target=aws_instance.web # Plan for one resource2terraform plan -target=module.vpc # Plan for entire module3terraform apply -target=aws_instance.web # Apply only one resource4terraform destroy -target=aws_instance.web # Destroy only one resourceReplace Resources
bash
1terraform apply -replace=aws_instance.web # Force recreation (Terraform 1.0+)2terraform taint aws_instance.web # Mark for recreation (deprecated)3terraform untaint aws_instance.web # Unmark for recreationVariables
Setting Variables
bash
1# Command line2terraform plan -var="region=us-west-2"3terraform plan -var='tags={"env":"prod","team":"ops"}'4
5# Variable files6terraform plan -var-file="production.tfvars"7terraform plan -var-file="secrets.tfvars"8
9# Environment variables (prefix with TF_VAR_)10export TF_VAR_region="us-west-2"11export TF_VAR_instance_type="t3.micro"12terraform planVariable Precedence (Lowest → Highest)
| Priority | Source |
|---|---|
| 1 (lowest) | Default values in variables.tf |
| 2 | terraform.tfvars or terraform.tfvars.json |
| 3 | *.auto.tfvars or *.auto.tfvars.json (alphabetical) |
| 4 | -var-file flag |
| 5 (highest) | -var flag or TF_VAR_ environment variables |
Modules
Use Modules
bash
1terraform get # Download modules only (without init)2terraform get -update # Update modules to latest versions3terraform init # Download modules + providersModule Sources
hcl
1# Local path2module "vpc" {3 source = "./modules/vpc"4}5
6# Terraform Registry7module "vpc" {8 source = "terraform-aws-modules/vpc/aws"9 version = "5.0.0"10}11
12# GitHub13module "vpc" {14 source = "github.com/org/repo//modules/vpc?ref=v1.0.0"15}16
17# S3 bucket18module "vpc" {19 source = "s3::https://bucket.s3.amazonaws.com/modules/vpc.zip"20}Terraform Cloud & Login
Authentication
bash
1terraform login # Authenticate with Terraform Cloud / HCP Terraform2terraform logout # Remove stored credentialsCloud Configuration
hcl
1terraform {2 cloud {3 organization = "my-org"4 workspaces {5 name = "my-workspace"6 }7 }8}Testing
Terraform Test (1.6+)
bash
1terraform test # Run all tests in tests/ directory2terraform test -filter=tests/vpc.tftest.hcl # Run specific test file3terraform test -verbose # Show detailed test outputTest File Example
hcl
1# tests/main.tftest.hcl2run "verify_instance" {3 command = plan4
5 assert {6 condition = aws_instance.web.instance_type == "t3.micro"7 error_message = "Instance type must be t3.micro"8 }9}10
11run "verify_tags" {12 command = apply13
14 assert {15 condition = aws_instance.web.tags["Environment"] == "production"16 error_message = "Environment tag must be production"17 }18}Output Formatting
Common Flags
| Flag | Description |
|---|---|
-json | Output in JSON format |
-no-color | Disable colored output |
-input=false | Disable interactive prompts |
-auto-approve | Skip approval prompt |
-compact-warnings | Show warnings in compact form |
-parallelism=N | Limit concurrent operations (default: 10) |
-lock=false | Don't hold state lock |
-lock-timeout=Ns | Wait N seconds for state lock |
-target=RESOURCE | Target specific resource |
-var="key=value" | Set variable value |
-var-file=FILE | Load variable values from file |
HCL Quick Reference
Common Functions
hcl
1# String2upper("hello") # "HELLO"3lower("HELLO") # "hello"4format("Hello, %s!", "world") # "Hello, world!"5join(", ", ["a", "b", "c"]) # "a, b, c"6split(",", "a,b,c") # ["a", "b", "c"]7replace("hello", "l", "L") # "heLLo"8trimspace(" hello ") # "hello"9
10# Numeric11min(1, 2, 3) # 112max(1, 2, 3) # 313ceil(4.2) # 514floor(4.8) # 415
16# Collection17length(["a", "b", "c"]) # 318contains(["a", "b"], "a") # true19merge({a=1}, {b=2}) # {a=1, b=2}20lookup({a=1}, "a", "default") # 121keys({a=1, b=2}) # ["a", "b"]22values({a=1, b=2}) # [1, 2]23flatten([[1,2],[3,4]]) # [1, 2, 3, 4]24distinct([1, 2, 2, 3]) # [1, 2, 3]25element(["a","b","c"], 1) # "b"26
27# Filesystem28file("path/to/file") # Read file contents29fileexists("path/to/file") # Check if file exists30templatefile("tpl.tftpl", {v=1}) # Render template file31
32# Encoding33base64encode("hello") # "aGVsbG8="34base64decode("aGVsbG8=") # "hello"35jsonencode({a = 1}) # '{"a":1}'36jsondecode('{"a":1}') # {a = 1}37yamlencode({a = 1}) # "a: 1\n"38
39# Network40cidrsubnet("10.0.0.0/16", 8, 1) # "10.0.1.0/24"41cidrhost("10.0.1.0/24", 5) # "10.0.1.5"42
43# Type conversion44tostring(42) # "42"45tonumber("42") # 4246tolist(["a", "b"]) # ["a", "b"]47toset(["a", "b", "a"]) # ["a", "b"]48tomap({a = 1}) # {a = 1}Common Resource Shortnames
| Provider | Resource | Common Usage |
|---|---|---|
| AWS | aws_instance | EC2 instances |
| AWS | aws_vpc | Virtual Private Cloud |
| AWS | aws_subnet | VPC subnets |
| AWS | aws_security_group | Security groups |
| AWS | aws_s3_bucket | S3 storage buckets |
| AWS | aws_iam_role | IAM roles |
| AWS | aws_lambda_function | Lambda functions |
| AWS | aws_rds_instance | RDS databases |
| Azure | azurerm_resource_group | Resource groups |
| Azure | azurerm_virtual_network | Virtual networks |
| Azure | azurerm_virtual_machine | Virtual machines |
| GCP | google_compute_instance | Compute instances |
| GCP | google_storage_bucket | Storage buckets |
| K8s | kubernetes_deployment | K8s deployments |
| Docker | docker_container | Docker containers |