Terraform Basics Cheatsheet
Quickly learn Terraform's core concepts, essential commands, and best practices for managing infrastructure as code.
Quick Overview
Terraform is an open-source Infrastructure as Code (IaC) tool by HashiCorp that enables you to define, provision, and manage cloud and on-premises resources using a declarative configuration language. It allows you to describe your desired infrastructure state in human-readable files (HCL), then automates the process of reaching and maintaining that state across various providers like AWS, Azure, GCP, and more. Terraform helps teams manage infrastructure consistently, reduce manual errors, and accelerate deployment cycles.
Current Stable Version: 1.14.8 (as of March 25, 2026)
One-Line Install (macOS via Homebrew):
brew tap hashicorp/tap
brew install hashicorp/tap/terraform
Getting Started
Let’s get Terraform installed and run your first “Hello, World!” equivalent by creating a local file.
-
Install Terraform:
- macOS: Use Homebrew as shown above.
- Linux (Debian/Ubuntu):
# Install the HashiCorp GPG key wget -O - https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg # Add the HashiCorp repository echo "deb [arch=$(dpkg --print-architecture) 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.list # Update and install Terraform sudo apt update && sudo apt install terraform - Windows: Download the appropriate
.zippackage from the official Terraform releases page. Unzip theterraform.exebinary to a directory (e.g.,C:\terraform) and add that directory to your system’sPATHenvironment variable.
-
Verify Installation:
terraform versionYou should see output similar to
Terraform v1.14.8. -
Your First Configuration (Hello World): Create a new directory (e.g.,
my-first-tf) and inside it, create a file namedmain.tfwith the following content:# main.tf # This resource simply runs a local command during the apply phase. resource "null_resource" "hello_world" { provisioner "local-exec" { command = "echo 'Hello, World! from Terraform'" } } # Define an output to show a message after applying output "message" { value = "Terraform applied successfully and said hello!" description = "A friendly confirmation message." } -
Initialize the Working Directory: Navigate to your
my-first-tfdirectory in your terminal and run:# Initialize the project, downloading any necessary providers terraform initThis command downloads the
nullprovider, which is implicitly required bynull_resource. -
Plan the Changes: See what Terraform will do before making any actual changes:
# Show the execution plan terraform planThis will output a plan showing that one
null_resourcewill be added. -
Apply the Changes: Execute the plan to create the resource (or run the command in this case):
# Apply the planned changes terraform applyType
yeswhen prompted to confirm the action. You’ll see “Hello, World! from Terraform” printed to your console, followed by the output message. -
Destroy the Resources: Clean up any resources created by Terraform:
# Destroy all resources defined in the configuration terraform destroyType
yeswhen prompted.
Core Concepts
Terraform operates on several key concepts that form its mental model.
| Concept | Description |
|---|---|
| Provider | A plugin that interacts with an API (e.g., AWS, Azure, GCP, Kubernetes, GitHub) to understand resources and perform actions. You configure providers to authenticate and specify desired regions/endpoints. |
| Resource | A block that defines a piece of infrastructure (e.g., a virtual machine, a network, a database, an S3 bucket). Resources have attributes that define their desired state. |
| Data Source | Allows Terraform to fetch information about existing infrastructure or external data (e.g., existing VPC ID, latest AMI ID). This lets you use resources not managed by the current Terraform configuration. |
| Module | A reusable, self-contained package of Terraform configurations. Modules encapsulate common infrastructure patterns, promoting reusability and maintainability. Every Terraform configuration is, itself, a root module. |
| State | Terraform maintains a state file (usually terraform.tfstate) that maps real-world infrastructure resources to your configuration. It tracks metadata, resource dependencies, and the current status of your managed infrastructure. Crucial for planning changes. |
| HCL | HashiCorp Configuration Language. The domain-specific language used by Terraform to write configurations. It’s designed to be human-readable and machine-friendly. |
| Plan | An execution plan is generated by Terraform to show what actions it will take (create, update, destroy) to move the infrastructure from its current state to the desired state defined in your configuration. |
Essential Commands
These commands form the core lifecycle of a Terraform project.
Project Initialization & Formatting
# Initialize a new or existing Terraform working directory.
# Downloads provider plugins, sets up backend (local or remote state).
terraform init
# Validate the syntax and configuration files in the current directory.
# Does not connect to the cloud provider.
terraform validate
# Rewrite Terraform configuration files to a canonical format.
# Improves readability and consistency.
terraform fmt
Infrastructure Lifecycle
# Generate and show an execution plan.
# This preview shows what actions Terraform will take without applying them.
terraform plan
# Apply the changes required to reach the desired state of the configuration.
# Prompts for confirmation unless `-auto-approve` is used.
terraform apply
# Destroy all resources managed by the current Terraform configuration.
# Prompts for confirmation unless `-auto-approve` is used.
terraform destroy
State Management & Inspection
# List all resources currently tracked in the Terraform state file.
terraform state list
# Show the attributes of a single resource as stored in the state file.
# Replace 'aws_s3_bucket.my_bucket' with your resource address.
terraform state show aws_s3_bucket.my_bucket
# Output values from your root module.
# Replace 'bucket_name' with the name of your output.
terraform output bucket_name
Common Patterns
Terraform’s power comes from structuring your configurations for reusability and maintainability.
Modular Architecture
Break down your infrastructure into reusable modules. Each module should encapsulate a specific component (e.g., networking, compute, storage). This promotes the DRY (Don’t Repeat Yourself) principle.
# modules/vpc/main.tf
# A simple VPC module
resource "aws_vpc" "main" {
cidr_block = var.cidr_block
tags = {
Name = "my-vpc-${var.environment}"
}
}
variable "cidr_block" {
description = "The CIDR block for the VPC."
type = string
}
variable "environment" {
description = "The environment name (dev, staging, prod)."
type = string
}
output "vpc_id" {
value = aws_vpc.main.id
description = "The ID of the created VPC."
}
# root_module/main.tf
# Calling the VPC module for a 'dev' environment
provider "aws" {
region = "us-east-1"
}
module "dev_vpc" {
source = "./modules/vpc" # Local path to your module
cidr_block = "10.0.0.0/16"
environment = "dev"
}
output "dev_vpc_id" {
value = module.dev_vpc.vpc_id
}
Tip: Modules should be provider-agnostic. Let the calling (root) module define and pass the required providers, rather than hardcoding them inside the module itself.
Environment-Based Deployments
Organize your configurations to manage multiple environments (dev, staging, prod) effectively, often leveraging modules. This usually involves separate directories for each environment, with each directory calling shared modules and passing environment-specific variables.
project/
├── modules/
│ └── vpc/
│ └── main.tf
│ └── variables.tf
│ └── outputs.tf
├── environments/
│ ├── dev/
│ │ └── main.tf
│ │ └── variables.tf
│ ├── staging/
│ │ └── main.tf
│ │ └── variables.tf
│ └── prod/
│ └── main.tf
│ └── variables.tf
Each environments/*/main.tf would call the modules/vpc (and other shared modules) with appropriate variable values for its respective environment.
Gotchas & Tips
Avoid common pitfalls to keep your Terraform projects robust and maintainable.
- Immutable Attributes Lead to Recreation: Be aware that changing certain resource attributes (e.g., an AWS EC2 instance type or an S3 bucket name) will cause Terraform to destroy the existing resource and create a new one, leading to downtime or data loss. Always review
terraform planoutput carefully for(forces replacement)messages.- Tip: Use modular design to isolate destructive changes. Move mutable parameters to separate resources if possible.
- Managing State: The
terraform.tfstatefile is critical.- Don’t modify it manually unless you absolutely know what you’re doing, and only after backing it up.
- Store state remotely (e.g., S3, Azure Blob Storage, HCP Terraform) and enable locking for collaborative environments to prevent concurrent modifications and data corruption.
- Sensitive Data: Never commit sensitive information (API keys, passwords) directly into your
.tffiles. Use environment variables, a secrets manager (like HashiCorp Vault, AWS Secrets Manager, Azure Key Vault), or Terraform’s built-insensitiveattribute for outputs. countvs.for_each: Misusing or changing betweencountandfor_each, or altering keys/indices, can lead to Terraform losing track of resources and recreating them unnecessarily. Usefor_eachwhen you have a map or set of unique strings/objects for stable identifiers.- Hardcoding Providers in Modules: Avoid defining
providerblocks directly within your modules. This couples the module to a specific account or region, limiting reusability. Instead, let the root module define and pass provider configurations to the modules. - Inline Blocks vs. Separate Resources: For resources like security group rules, prefer standalone
aws_security_group_ruleresources over inlineingress/egressblocks withinaws_security_group. This allows for greater flexibility and composability, enabling module users to inject additional rules without modifying the module’s source. - File Paths in Modules: When a module references local files (e.g., user data scripts), use
path.moduleorpath.rootto ensure portability, rather than relying onpath.cwd(current working directory), which can vary based on where Terraform is executed.
Next Steps
- Official Terraform Documentation: The ultimate source for in-depth information, provider details, and advanced topics. https://developer.hashicorp.com/terraform/docs
- Terraform Registry: Discover and use publicly available Terraform modules and providers. https://registry.terraform.io/
- HCL Language Documentation: Dive deeper into HashiCorp Configuration Language syntax. https://developer.hashicorp.com/terraform/language
Source: z2h.fyi/cheatsheets/terraform-basics — Zero to Hero cheatsheets for developers.
Source: z2h.fyi/cheatsheets/terraform-basics — Zero to Hero cheatsheets for developers.