Guides
Terraform Modules Explained: Reuse VPC and EC2 Code
By Ravindra Bagale, DevOps trainer · LinkedIn · Published: · Last updated:
Put VPC and EC2 in module folders with variables and outputs, call them from root, wire outputs to inputs, init, validate, and pin versions.
Friends, a module is a function for infrastructure. Chala mitrano — call it with different variables for Mumbai and Frankfurt, do not copy folders.
मित्रांनो, module म्हणजे infrastructure साठी function. Chala mitrano — वेगळ्या variables ने call करा, folders copy करू नका.
मित्रों, module मतलब infrastructure का function। Chala mitrano — अलग variables से call करें, folders copy न करें।
Quick answer
Hold this vertical picture:
- Create modules/vpc and modules/ec2.
- Add variables and outputs.
- Call from root main.tf.
- Wire vpc output to ec2.
- init, validate, plan; pin refs.
Language: English · मराठी · हिंदी
Module reuse
Stop copy-paste drift across envs.
Why: Two edited copies diverge every week.
What: Folder modules with inputs/outputs.
How: Root calls with different vars.
Example 1: Module folder layout
Type this:
mkdir -p /tmp/tfmod/modules/vpc && printf '%s\n' 'variable "cidr" { type = string }' 'output "vpc_id" { value = "vpc-demo" }' > /tmp/tfmod/modules/vpc/main.tf && ls /tmp/tfmod/modules/vpc
You will see:
What it means: A module is a folder with variables, resources, outputs.
Example 2: Root calls the module
Type this:
printf '%s\n' 'module "vpc" {' ' source = "./modules/vpc"' ' cidr = "10.0.0.0/16"' '}' > /tmp/tfmod/main.tf && cat /tmp/tfmod/main.tf
You will see:
What it means: source points at the folder; inputs are arguments.
Example 10: Do not copy-paste stacks
Type this:
printf '%s\n' 'ok: one vpc module called from dev and prod with different cidr'
You will see:
ok: one vpc module called from dev and prod with different cidr
What it means: Copy-paste drifts — modules stop that.
Outputs feed the next module.
Why: Hard-coded subnet ids break reuse.
What: module.vpc outputs → module.web inputs.
How: Root outputs for CI.
Example 3: EC2 module sketch
Type this:
mkdir -p /tmp/tfmod/modules/ec2 && printf '%s\n' 'variable "instance_type" { type = string }' 'variable "subnet_id" { type = string }' 'output "instance_id" { value = "i-demo" }' > /tmp/tfmod/modules/ec2/main.tf && cat /tmp/tfmod/modules/ec2/main.tf
You will see:
variable "instance_type" { type = string }
What it means: EC2 module takes subnet from VPC output later.
Example 4: Wire VPC output to EC2
Type this:
printf '%s\n' 'module "web" {' ' source = "./modules/ec2"' ' instance_type = "t3.micro"' ' subnet_id = module.vpc.vpc_id' '}' >> /tmp/tfmod/main.tf && tail -6 /tmp/tfmod/main.tf
You will see:
subnet_id = module.vpc.vpc_id
What it means: Outputs become inputs — Flipkart-style reuse.
Example 9: Output from root
Type this:
printf '%s\n' 'output "web_id" { value = module.web.instance_id }' > /tmp/tfmod/outputs.tf && cat /tmp/tfmod/outputs.tf
You will see:
output "web_id" { value = module.web.instance_id }
What it means: Root outputs expose what CI needs.
Terraform loads module source.
Why: Skipping init leaves empty module cache.
What: init; validate; plan.
How: Addresses use module. prefix.
Example 5: terraform init for modules
Type this:
printf '%s\n' 'terraform init'
You will see:
What it means: Downloads/copies module source into .terraform.
Example 6: Plan shows module addresses
Type this:
printf '%s\n' 'terraform plan # addresses look like module.vpc.aws_vpc.this'
You will see:
terraform plan # addresses look like module.vpc.aws_vpc.this
What it means: Module prefix keeps state tidy.
Example 11: Validate
Type this:
printf '%s\n' 'terraform validate'
You will see:
What it means: Catches type mistakes before plan.
Version pins; clear inputs/outputs.
Why: Floating main tags surprise prod.
What: ref=vX.Y.Z; document variables.
How: Resources stay inside the module.
Example 7: Version pin for remote modules
Type this:
printf '%s\n' 'source = "git::ssh://git.example.internal/tf/vpc.git?ref=v1.2.0"'
You will see:
source = "git::ssh://git.example.internal/tf/vpc.git?ref=v1.2.0"
What it means: Pin ref= — never float on main for prod.
Example 8: Locals for defaults
Type this:
printf '%s\n' 'locals { name_prefix = "pay-dev" }'
You will see:
locals { name_prefix = "pay-dev" }
What it means: Locals keep repeated tags DRY.
Example 12: Module contract
Type this:
printf '%s\n' 'Inputs = variables; outputs = return values; resources stay private inside'
You will see:
Inputs = variables; outputs = return values; resources stay private inside
What it means: Interview one-liner at Cognizant.
1 Create module folder 2 variables + outputs 3 module block in root 4 wire outputs→inputs 5 init/validate/plan 6 pin versions
Declare variable in the module; pass it from root.
Check relative path or git ref.
Ravindra Bagale's Tip
At Accenture reviews, unpinned module sources on main are a finding. Always ref=vX.Y.Z for shared modules.
Accenture reviews मध्ये main वर unpinned module = finding. Shared modules साठी ref=vX.Y.Z.
Accenture reviews में main पर unpinned module = finding। Shared modules के लिए ref=vX.Y.Z।
Q1. What is a module?
Reusable Terraform folder
Q2. How does root use it?
module block + source
Q3. Wire pattern?
output → input
Q4. Why pin ref?
Reproducible prod
Q5. validate?
Catch type errors early
Q6. Copy-paste stacks?
No — call the module
Reading tracking
Mark this guide when you finish. Your browser remembers it on this device.
module folder → call → wire → init → plan.
Did you understand? Let us try it once more.
Frequently asked questions
Module vs resource?
Module groups resources with a contract.
Local vs remote source?
Local for learning; remote pinned for teams.
Can modules nest?
Yes — keep depth small.
Where do providers go?
Usually root; pass aliases carefully.
Count/for_each on modules?
Supported — advanced.
Why outputs?
Hide internals; expose only what callers need.