Cheatsheet Terraform
Infraestrutura como código para provisionar cloud e serviços
Terraform
CLI
Initialize
terraform init
terraform init -upgrade
terraform init -backend=false
Initialize the directory and providers.
Output and Inspection
terraform output
terraform output public_ip
terraform show
terraform state list
See outputs and the current state.
Plan and Apply
terraform plan
terraform plan -out=plan.tfplan
terraform apply
terraform apply plan.tfplan
terraform apply -auto-approve
Preview and apply changes.
Destroy
terraform destroy
terraform destroy -target=aws_instance.web
terraform destroy -auto-approve
Remove all the infrastructure.
Formatting and Validation
terraform fmt
terraform fmt -check
terraform validate
terraform plan -detailed-exitcode
Format and validate code.
HCL and Blocks
File Structure
main.tf # main resources
variables.tf # input variables
outputs.tf # outputs
providers.tf # provider configuration
terraform.tfvars # values
modules/ # reusable modules
Project organization.
Data Types
string = "text"
number = 42
bool = true
list = ["a", "b", "c"]
map = { key = "value" }
object = { name = "x", port = 80 }
tuple = [1, "two", true]
Types available in HCL.
Expressions
var.name
local.config
resource.type.name.attribute
data.type.name.attribute
module.name.output
terraform.workspace
References to values.
Dynamic Blocks
dynamic "ingress" {
for_each = var.ports
content {
from_port = ingress.value
to_port = ingress.value
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}Generate repeated blocks.
Resources
Define a Resource
resource "aws_instance" "web" {
ami = "ami-12345"
instance_type = "t3.micro"
tags = {
Name = "Web Server"
}
}Create an infrastructure resource.
Lifecycle
resource "aws_instance" "web" {
# ...
lifecycle {
create_before_destroy = true
prevent_destroy = true
ignore_changes = [tags]
}
}Control the lifecycle.
Data Sources
data "aws_ami" "ubuntu" {
most_recent = true
owners = ["099720109477"]
filter {
name = "name"
values = ["ubuntu-*-22.04-*"]
}
}Read existing data.
Dependencies
resource "aws_instance" "app" {
# implicit dependency
subnet_id = aws_subnet.main.id
# explicit dependency
depends_on = [aws_iam_role.app]
}Creation order.
for_each and count
resource "aws_instance" "servers" {
for_each = toset(["web", "api", "db"])
instance_type = "t3.micro"
tags = { Name = each.value }
}
resource "aws_subnet" "sub" {
count = 3
cidr_block = "10.0.${count.index}.0/24"
}Create multiple instances.
Variables and Outputs
Define Variables
variable "instance_type" {
description = "Instance type"
type = string
default = "t3.micro"
}
variable "ports" {
type = list(number)
default = [80, 443]
}Module/project inputs.
Validation
variable "env" {
type = string
validation {
condition = contains(
["dev", "staging", "prod"],
var.env)
error_message = "Invalid env."
}
}Validate inputs.
Outputs
output "public_ip" {
description = "Server IP"
value = aws_instance.web.public_ip
}
output "config" {
value = aws_instance.web
sensitive = true
}Export values.
Locals
locals {
project_name = "my-app"
common_tags = {
Project = local.project_name
Env = var.environment
}
subnets = [
for i in range(3) :
"10.0.${i}.0/24"
]
}Internal computed values.
Modules
Use a Module
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.0.0"
name = "my-vpc"
cidr = "10.0.0.0/16"
azs = ["eu-west-1a", "eu-west-1b"]
}Use a module from the registry.
Local Module
module "app" {
source = "./modules/app"
name = "web"
instance_type = "t3.small"
subnet_id = module.vpc.private_subnets[0]
}Custom local module.
Create a Module
# modules/app/main.tf
variable "name" { type = string }
variable "instance_type" { type = string }
resource "aws_instance" "this" {
instance_type = var.instance_type
}
output "id" {
value = aws_instance.this.id
}
Structure of a module.
Module Sources
source = "./modules/local"
source = "terraform-aws-modules/vpc/aws"
source = "github.com/user/repo//dir"
source = "s3::https://s3-eu-west-1.amazonaws.com/bucket/module.zip"
source = "git::https://github.com/user/repo.git?ref=v1.0"
Available origins.
State
State Commands
terraform state list
terraform state show aws_instance.web
terraform state mv old new
terraform state rm aws_instance.web
terraform state pull > backup.json
Manage the state.
Remote Backend (S3)
terraform {
backend "s3" {
bucket = "my-tf-state"
key = "prod/terraform.tfstate"
region = "eu-west-1"
dynamodb_table = "tf-locks"
encrypt = true
}
}Shared state with locking.
Import Resources
terraform import aws_instance.web i-12345
# or with an import block (TF 1.5+):
import {
to = aws_instance.web
id = "i-12345"
}
Adopt existing resources.
Refresh and Taint
terraform refresh
terraform apply -refresh-only
terraform taint aws_instance.web
terraform untaint aws_instance.web
Sync and mark for recreation.
Providers
Configure a Provider
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "eu-west-1"
}Define the provider and version.
Multiple Providers
provider "aws" {
region = "eu-west-1"
}
provider "aws" {
alias = "us"
region = "us-east-1"
}
resource "aws_instance" "dr" {
provider = aws.us
}Use multiple regions/accounts.
Terraform Version
terraform {
required_version = ">= 1.5.0"
required_providers {
aws = { version = "~> 5.0" }
random = { version = "~> 3.5" }
}
}Pin versions.
Common Providers
hashicorp/aws
hashicorp/azurerm
hashicorp/google
hashicorp/kubernetes
hashicorp/helm
hashicorp/null (provisioners)
hashicorp/random
Popular providers.
Advanced
Workspaces
terraform workspace list
terraform workspace new staging
terraform workspace select prod
terraform workspace show
# use in code:
name = "${terraform.workspace}-app"
Isolated environments.
Useful Functions
join("-", ["a", "b"]) # "a-b"
lookup(map, key, default)
merge(map1, map2)
length(list)
format("%s-%s", a, b)
try(expr, fallback)
coalesce(a, b, c)Manipulation functions.
Provisioners
resource "aws_instance" "web" {
# ...
provisioner "remote-exec" {
inline = [
"sudo apt update",
"sudo apt install -y nginx"
]
}
connection {
type = "ssh"
user = "ubuntu"
private_key = file("~/.ssh/id_rsa")
}
}Run after creation.
Best Practices
# • Use remote state with locking
# • Small, reusable modules
# • Variables with description and type
# • terraform fmt + validate in CI
# • Never commit .tfstate
# • Use pinned provider versions
# • Separate by environment (workspaces or dirs)
Usage recommendations.