By Fatskills Exam Guides Team — the exam nerds behind 28,500+ quizzes and 2.1M practice questions across 500+ global exams.
(Zero fluff, 100% actionable for real projects & certs)
What it is: Terraform modules let you package reusable infrastructure (e.g., a VPC, an ECS cluster, or a secure S3 bucket) into a single unit. Versioning those modules ensures you can: - Upgrade safely (e.g., "v1.2 adds encryption, but v1.1 doesn’t"). - Roll back if a new version breaks production. - Share modules across teams without breaking existing deployments.
Why it matters in production: Imagine you’re a cloud engineer at a fintech startup. Your team deploys 50+ AWS accounts using the same Terraform module for a secure VPC. One day, a junior engineer updates the module to add a new subnet—but accidentally removes the enable_dns_support flag. Without versioning, every single account deploys the broken change instantly. With versioning, you can: - Pin accounts to v1.0 (stable). - Test v1.1 in staging. - Roll out only after validation.
enable_dns_support
v1.0
v1.1
Real-world scenario: You inherit a legacy Terraform codebase where all modules are referenced via git::https://github.com/company/terraform-aws-vpc.git. Every terraform apply pulls the latest commit—meaning a single git push can break production. Your mission: Lock down versions so deployments are predictable.
git::https://github.com/company/terraform-aws-vpc.git
terraform apply
git push
ref=main
version = "~> 1.2"
~>
=
MAJOR.MINOR.PATCH
1.2.3
MAJOR
MINOR
PATCH
source = "git::https://github.com/org/repo.git?ref=v1.2.0"
ref=v1.2.0
ref=abc123
source = "./modules/vpc"
vpc_id
subnet_ids
README.md
cidr_block = "10.0.0.0/16"
validation
terraform.lock.hcl
module "vpc" { source = "..." }
module "prod_vpc"
module "vpc"
>= 1.0.0
Convert a legacy module from "latest commit" to versioned releases.
terraform-aws-vpc
terraform-aws-vpc/ ? main.tf # VPC, subnets, etc. ? variables.tf # Input variables ? outputs.tf # Exposed values ? README.md # Documentation
main.tf
variable "cidr_block" { type = string }
variable "tags" { type = map(string) default = {} }
output "vpc_id" { value = aws_vpc.this.id } ```
bash git add . git commit -m "Initial VPC module"
bash git tag -a v1.0.0 -m "Initial release" git push origin v1.0.0
hcl module "vpc" { source = "git::https://github.com/your-org/terraform-aws-vpc.git?ref=v1.0.0" cidr_block = "10.0.0.0/16" tags = { Environment = "prod" } }
bash terraform init
v1.0.0
.terraform/modules
hcl # main.tf (in the module repo) resource "aws_vpc" "this" { cidr_block = var.cidr_block # enable_dns_support removed (BREAKING CHANGE) tags = var.tags }
bash git add . git commit -m "Remove DNS support (breaking change)" git tag -a v2.0.0 -m "Breaking: Remove DNS support" git push origin v2.0.0
v2.0.0
hcl module "vpc" { source = "git::https://github.com/your-org/terraform-aws-vpc.git?ref=v2.0.0" cidr_block = "10.0.0.0/16" tags = { Environment = "prod" } }
bash terraform init -upgrade # Forces re-download of the module terraform plan # Verify the change terraform apply
Instead of pinning to v2.0.0, allow non-breaking updates (e.g., bug fixes):
module "vpc" { source = "git::https://github.com/your-org/terraform-aws-vpc.git?ref=v2.0.0" version = "~> 2.0" # Allows 2.0.1, 2.1.0, but not 3.0.0 cidr_block = "10.0.0.0/16" }
~> 2.0
2.x.x
3.0.0
~> 2.0.0
2.0.x
2.1.0
provider "registry.terraform.io/hashicorp/aws" { version = "5.23.0" constraints = "~> 5.0" hashes = [ "h1:...", ] }
module "vpc" { source = "git::https://github.com/your-org/terraform-aws-vpc.git?ref=v2.0.0" version = "2.0.0" dir = ".terraform/modules/vpc" } 2. Commit the lock file to Git:bash git add terraform.lock.hcl git commit -m "Add module lock file" ```
2. Commit the lock file to Git:
git-secrets
trivy
tags = var.tags
CHANGELOG.md
terraform validate
check
security_group_id
terraform plan -out=tfplan
cidr_block
1.3.0
2.0.0
~> 1.2
>= 1.2.0, < 2.0.0
= 1.2.3 (too restrictive)
= 1.2.3
"You need to update a module but avoid breaking changes. Which version should you use?"
1.2.x
1.3.x
>= 1.0.0 (allows 2.0.0)
"Where does Terraform store downloaded modules?"
.terraform/modules/
.terraform/providers/
version = "1.2.0"
= 1.2.0
Challenge: You have a module referenced like this:
module "s3_bucket" { source = "git::https://github.com/company/terraform-aws-s3.git" }
Problem: Every terraform apply pulls the latest commit, which is risky.
Task:1. Tag the module repo with v1.0.0.2. Update the module call to use v1.0.0 with a version constraint.3. Verify the lock file is updated.
Solution:1. Tag the module: bash git tag -a v1.0.0 -m "Initial release" git push origin v1.0.02. Update the module call: hcl module "s3_bucket" { source = "git::https://github.com/company/terraform-aws-s3.git?ref=v1.0.0" version = "~> 1.0" }3. Run terraform init -upgrade and check terraform.lock.hcl.
hcl module "s3_bucket" { source = "git::https://github.com/company/terraform-aws-s3.git?ref=v1.0.0" version = "~> 1.0" }
terraform init -upgrade
Why it works: - ref=v1.0.0 pins the exact version. - version = "~> 1.0" allows future 1.x.x updates but not 2.0.0.
ref=v1.0.0
version = "~> 1.0"
1.x.x
source = "terraform-aws-modules/vpc/aws"
version = "~> 3.0"
version = "= 1.2.0"
.terraform.lock.hcl
git tag -a v1.0.0 -m "Initial release"
terraform providers mirror ./mirror
Join 4M+ learners. Unlock unlimited quizzes, wrong-answer tracking, flashcards + reminders, study guides, and 1-on-1 challenges.