Why Modules?
Without modules, Terraform projects become monolithic walls of configuration. Modules let you:
- Organize — group related resources logically
- Reuse — use the same pattern across projects
- Abstract — hide complexity behind simple interfaces
- Share — publish modules for your team or community
Module Structure
modules/
vpc/
main.tf
variables.tf
outputs.tf
ec2/
main.tf
variables.tf
outputs.tfMaster this topic with hands-on labs
Go beyond reading — build real projects in sandboxed environments with expert video guidance.
Browse Courses →Creating a Module
modules/vpc/main.tf:
resource "aws_vpc" "main" {
cidr_block = var.cidr_block
enable_dns_hostnames = true
tags = merge(var.tags, {
Name = "${var.project}-vpc"
})
}
resource "aws_subnet" "public" {
count = length(var.public_subnets)
vpc_id = aws_vpc.main.id
cidr_block = var.public_subnets[count.index]
availability_zone = var.azs[count.index]
tags = merge(var.tags, {
Name = "${var.project}-public-${count.index}"
})
}modules/vpc/variables.tf:
variable "cidr_block" {
type = string
}
variable "public_subnets" {
type = list(string)
}
variable "azs" {
type = list(string)
}
variable "project" {
type = string
}
variable "tags" {
type = map(string)
default = {}
}modules/vpc/outputs.tf:
output "vpc_id" {
value = aws_vpc.main.id
}
output "subnet_ids" {
value = aws_subnet.public[*].id
}Using a Module
module "vpc" {
source = "./modules/vpc"
cidr_block = "10.0.0.0/16"
public_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
azs = ["eu-west-1a", "eu-west-1b"]
project = "myapp"
tags = local.common_tags
}
# Reference module outputs
resource "aws_instance" "web" {
subnet_id = module.vpc.subnet_ids[0]
}Get weekly IT automation tips
Docker, Ansible, Terraform, MLOps — curated insights delivered to your inbox. No spam.
Subscribe Free →Terraform Registry Modules
Use community modules from the Terraform Registry:
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.0.0"
name = "my-vpc"
cidr = "10.0.0.0/16"
}Best Practices
- Keep modules focused — one concern per module
- Version your modules — use Git tags or registry versions
- Document inputs/outputs — add descriptions to all variables
- Use sensible defaults — make modules easy to use out of the box
- Don't hardcode — everything configurable via variables
Learn More
Build reusable Terraform modules in our Terraform for Beginners course.
---
Ready to go deeper? Check out our hands-on course: Terraform for Beginners — practical exercises you can follow along on your own machine.
Ready to learn by doing?
Stop reading tutorials — start building. Expert video courses with hands-on labs in real sandboxed environments.
Related Articles
Terraform Modules Best Practices
Write reusable Terraform modules. Structure, variables, outputs, semantic versioning, automated testing, and registry publishing.
Tofu vs Terraform Comparison
OpenTofu forked Terraform after the BSL license change. Compare features, compatibility, licensing, and ecosystem to decide which IaC tool fits your team.
Ansible vs Terraform When to Use
Ansible and Terraform solve different infrastructure problems. Learn when to use each, when to use both together, and how they complement each other.
Terraform Providers Deep Dive
Terraform providers for multi-cloud. Configuration, version pinning, aliases for multi-region, and debugging provider issues.
Terraform Security Practices
Secure your Terraform workflows — manage secrets, control access, encrypt state, and implement policy-as-code for safe infrastructure deployments.
Terraform State Management
Understand Terraform state — how it tracks resources, why it's critical, and best practices for remote state, locking, and team workflows.
Explore topics
Browse more articles on the topics covered here.