What are Modules?
A module is a reusable package of Terraform files that you call with inputs and read outputs from.
A module is a container for a set of resources used together. Every Terraform configuration is already a module — the root module — but you can factor common patterns into child modules and reuse them.
Why modules?
- Reuse a proven design (a VPC, a web service) across projects.
- Hide complexity behind a clean set of inputs and outputs.
- Standardize how your team builds infrastructure.
Example
# A tiny child module: modules/s3-bucket/main.tf
variable "name" { type = string }
resource "aws_s3_bucket" "this" {
bucket = var.name
}
output "arn" {
value = aws_s3_bucket.this.arn
}When to use it
- A platform team publishes a vpc module that provisions a standard VPC with public and private subnets, and 10 application teams reuse it without writing VPC code.
- A company builds a database module encapsulating RDS, parameter group, subnet group, and security group; each service team calls it with just a few variables.
- A DevOps engineer wraps Lambda, IAM role, and CloudWatch log group into a module so developers create new functions by writing a 5-line module call.
More examples
Simple module directory layout
Shows the standard three-file module layout (main, variables, outputs) and how the root module calls it.
modules/
vpc/
main.tf # resources: aws_vpc, aws_subnet, aws_igw
variables.tf # inputs: cidr_block, name, azs
outputs.tf # outputs: vpc_id, subnet_ids
root/
main.tf # calls module "vpc" { source = "../modules/vpc" }Module internal main.tf
Shows the internal resource definitions of a reusable VPC module that uses var.* for all caller-supplied values.
# modules/vpc/main.tf
resource "aws_vpc" "this" {
cidr_block = var.cidr_block
enable_dns_hostnames = true
tags = { Name = var.name }
}
resource "aws_internet_gateway" "this" {
vpc_id = aws_vpc.this.id
}Why modules beat copy-paste
Illustrates that a module centralizes logic so a single fix propagates to all callers, eliminating copy-paste drift.
# Without a module: 80 lines duplicated per service
# services/api/main.tf (80 lines VPC code)
# services/worker/main.tf (80 lines VPC code, slightly different)
# With a module: one call per service
# services/api/main.tf
# module "vpc" {
# source = "../../modules/vpc"
# cidr_block = "10.1.0.0/16"
# name = "api"
# }
# A bug fix in the module benefits all callers at once
Discussion