Terraform Tutorial — Why Modules?
As your infrastructure grows, you’ll find yourself repeating the same patterns — VPCs, security groups, EC2 instances — across multiple environments. Modules solve this problem.
The Problem: Copy-Paste Infrastructure
Without modules:
environments/
├── dev/
│ ├── main.tf ← VPC + EC2 + S3 (dev values)
│ └── variables.tf
├── staging/
│ ├── main.tf ← VPC + EC2 + S3 (staging values, copy-pasted!)
│ └── variables.tf
└── prod/
├── main.tf ← VPC + EC2 + S3 (prod values, copy-pasted!)
└── variables.tf
Problems:
- Bug fix requires updating three files
- Configurations drift apart over time
- No guarantee environments are consistent
The Solution: Modules
With modules:
modules/
├── vpc/
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
└── app/
├── main.tf
├── variables.tf
└── outputs.tf
environments/
├── dev/main.tf ← calls module "vpc" + module "app" with dev values
├── staging/main.tf ← calls module "vpc" + module "app" with staging values
└── prod/main.tf ← calls module "vpc" + module "app" with prod values
Benefits of Modules
| Benefit | Description |
|---|---|
| DRY | Write once, use everywhere |
| Consistency | Same infrastructure pattern across environments |
| Encapsulation | Hide complexity behind a simple interface |
| Testability | Test the module once, trust it in all environments |
| Versioning | Pin module versions for stability |
| Team collaboration | One team maintains the module, others consume it |
Module Types
| Type | Source | Example |
|---|---|---|
| Local | File path | source = "./modules/vpc" |
| Registry | Terraform Registry | source = "terraform-aws-modules/vpc/aws" |
| Git | Git repository | source = "git::https://github.com/org/module.git" |
| S3 | S3 bucket | source = "s3::https://bucket.s3.amazonaws.com/module.zip" |
What’s Next?
Let’s look at the standard structure of a Terraform module.