Terraform Cheatsheet
Modules
Use this Terraform reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
What Modules Are
A module is any directory with .tf files. Every Terraform project is the root module. You call child modules to encapsulate reusable infrastructure patterns.
Calling a Module
module "vpc" { source = "./modules/vpc" # local path # source = "hashicorp/vpc/aws" # Terraform Registry # source = "git::https://github.com/org/modules.git//vpc?ref=v1.2.0" # pass values to the module's input variables cidr_block = "10.0.0.0/16" environment = var.environment az_count = 3 } # Consume module outputs output "vpc_id" { value = module.vpc.vpc_id }
Module Sources
| Source type | Example |
|---|---|
| Local path | ./modules/vpc |
| Terraform Registry | "terraform-aws-modules/vpc/aws" |
| Registry with version | version = "5.1.0" (separate arg) |
| GitHub HTTPS | "git::https://github.com/org/repo.git//subdir" |
| GitHub SSH | "git::ssh://git@github.com/org/repo.git?ref=v1.0" |
| S3 bucket | "s3::https://s3.amazonaws.com/bucket/module.zip" |
| HTTP archive | "https://example.com/vpc.zip" |
# Registry module with version pinning module "vpc" { source = "terraform-aws-modules/vpc/aws" version = "~> 5.0" name = "my-vpc" cidr = "10.0.0.0/16" azs = ["us-east-1a", "us-east-1b", "us-east-1c"] }
Writing a Module
modules/
└── vpc/
├── main.tf # resources
├── variables.tf # inputs
├── outputs.tf # exports
└── versions.tf # required_providers# modules/vpc/variables.tf variable "cidr_block" { type = string description = "CIDR block for the VPC" } variable "environment" { type = string default = "dev" }
# modules/vpc/main.tf resource "aws_vpc" "main" { cidr_block = var.cidr_block tags = { Environment = var.environment } } resource "aws_subnet" "public" { count = 2 vpc_id = aws_vpc.main.id cidr_block = cidrsubnet(var.cidr_block, 8, count.index) availability_zone = data.aws_availability_zones.available.names[count.index] }
# modules/vpc/outputs.tf output "vpc_id" { value = aws_vpc.main.id } output "public_subnet_ids" { value = aws_subnet.public[*].id }
Module Meta-Arguments
module "app" { source = "./modules/app" count = var.enable_app ? 1 : 0 # conditional module } module "region" { source = "./modules/region" for_each = toset(["us-east-1", "us-west-2"]) # multiple instances region = each.key } module "app" { source = "./modules/app" depends_on = [module.vpc] # explicit dependency providers = { # pass aliased provider aws = aws.west } }
Passing Providers to Modules
# Root config provider "aws" { region = "us-east-1" } provider "aws" { alias = "west"; region = "us-west-2" } module "west_resources" { source = "./modules/app" providers = { aws = aws.west } }
# modules/app/versions.tf — declare expected provider
terraform {
required_providers {
aws = { source = "hashicorp/aws" }
}
}Module Outputs in for_each
module "bucket" { for_each = toset(["logs", "backups"]) source = "./modules/s3-bucket" name = each.key } output "bucket_arns" { value = { for k, m in module.bucket : k => m.bucket_arn } }
Popular Public Modules
| Module | Registry path |
|---|---|
| AWS VPC | terraform-aws-modules/vpc/aws |
| AWS EKS | terraform-aws-modules/eks/aws |
| AWS RDS | terraform-aws-modules/rds/aws |
| AWS ALB | terraform-aws-modules/alb/aws |
| AWS IAM | terraform-aws-modules/iam/aws |
| GCP Network | terraform-google-modules/network/google |
Module Commands
terraform init # downloads/updates all modules terraform get # download modules only (no provider init) terraform get -update # re-download modules (pick up changes)
Module Versioning Best Practices
- Pin Registry modules with
version = "~> X.Y"(pessimistic constraint) - Pin Git modules with
?ref=v1.2.3(tag), not branch names - Run
terraform init -upgradeintentionally when you want to update