L3. Mastering Terraform Modules: Clean, Reusable Infrastructure for DevOps Beginners
One of the most powerful yet underused features of Terraform is the concept of modules.
If you’re a beginner, student, or new DevOps engineer, you’ve probably written Terraform code in one big file. But what happens when your infrastructure grows? What if your team wants to reuse the same code across environments or projects?
Welcome to the world of Terraform modules - a structured, maintainable, and reusable way to write your infrastructure as code.
Let’s explore this in-depth.
📦 What is a Terraform Module?
A module in Terraform is simply a folder that contains .tf files - your Terraform configurations - which can be reused across projects.
A module is to Terraform what a function is to programming.
Why Use Modules?
✅ Avoid code duplication
✅ Increase reusability across teams and environments
✅ Enable better testing and debugging
✅ Enforce standards across infrastructure
✅ Encourage team collaboration with ownership and modular thinking
🔧 Real-World Analogy
Imagine you're working at a company like amazon.com and the app is a monolithic Java codebase with 1 million+ lines of code. When there's a bug, it's hard to know who wrote what, where to fix it, and how to test it without deploying the entire app.
The fix? Microservices - smaller, decoupled, maintainable codebases.
Similarly in Terraform:
Without modules, your .tf file will grow with:
EC2 Instances
S3 Buckets
VPCs
Lambda Functions
Load Balancers
EKS clusters
...and more.
It becomes impossible to maintain or collaborate on.
That’s why we adopt a modular approach in Terraform - breaking things into small, logical, reusable units.
🛠 Creating a Basic Terraform Module (Step-by-Step)
Let’s build a reusable EC2 instance module.
📁 Folder Structure
terraform-project/
├── main.tf
├── modules/
│ └── ec2_instance/
│ ├── main.tf
│ ├── variables.tf
│ ├── outputs.tf
🔨 Step 1: Inside modules/ec2_instance/main.tf
resource "aws_instance" "example" {
ami = var.ami_value
instance_type = var.instance_type_value
subnet_id = var.subnet_id_value
}
📥 Step 2: Define Variables in modules/ec2_instance/variables.tf
variable "ami_value" {
description = "AMI ID for the EC2 instance"
}
variable "instance_type_value" {
description = "EC2 instance type"
}
variable "subnet_id_value" {
description = "Subnet ID for the instance"
}
📤 Step 3: Output Public IP in modules/ec2_instance/outputs.tf
output "public_ip" {
value = aws_instance.example.public_ip
}
🧪 Step 4: Consume the Module in Root main.tf
provider "aws" {
region = "us-east-1"
}
module "ec2_instance" {
source = "./modules/ec2_instance"
ami_value = "ami-0c55b159cbfafe1f0"
instance_type_value = "t2.micro"
subnet_id_value = "subnet-0123456789abcdef0"
}
📌 How It Works
When you run:
terraform init
terraform apply
Terraform will:
Load the
ec2_instancemoduleInject the variables you passed
Create the EC2 instance
Output the public IP
🔁 Why This Is So Powerful
Imagine this scenario:
You have 3 dev teams, each needing EC2 instances with different configurations.
With modules:
You reuse the same module
Just pass different
ami,instance_type, andsubnet_idNo duplicated code
Additional Benefits:
🧱 Modularity – Break infrastructure into building blocks
🔄 Reusability – Use the same logic across teams
🧪 Testability – Test modules in isolation
🔐 Security – Keep secrets in
terraform.tfvars(not in code)📚 Documentation & Ownership – Clear inputs and outputs make team collaboration easier
🔐 Optional: Use terraform.tfvars to Supply Values
Create a terraform.tfvars file in your root directory:
ami_value = "ami-0c55b159cbfafe1f0"
instance_type_value = "t2.micro"
subnet_id_value = "subnet-0123456789abcdef0"
Then just run:
terraform apply
Terraform will automatically pick up values from this file.
🗃️ Where Should You Store Modules?
In the same repo (like above)
In a separate GitHub repo (shared across projects)
Use Terraform Registry (like DockerHub for modules)
❗ In production, avoid unknown public modules unless you trust the source.
Companies usually create private module registries in GitHub or Terraform Cloud.
🚀 Pro Tip: Modules Scale With Your Org
Let’s say your team writes modules for:
ec2_instances3_bucketeks_clustervpcalb
Now, internal developers can simply consume those like building blocks - without writing full configurations.
module "s3_bucket" {
source = "git::https://github.com/org/modules.git//s3"
bucket_name = "my-app-logs"
}
✅ Summary
Terraform modules are the secret weapon for writing production-grade infrastructure:
| Benefit | Description |
| Modularity | Smaller, manageable components |
| Reusability | Use same code across environments/teams |
| Security | Keep sensitive data out of source control |
| Collaboration | Clear ownership and shared modules |
| Scalability | Codebase stays clean as infra grows |
🔚 Final Thoughts
If you’re serious about mastering Terraform, start thinking in modules today.
Instead of managing huge .tf files, break your infrastructure into clean, reusable, and testable units - just like developers do with microservices.
"Good DevOps is modular. Great DevOps is reusable."