Skip to main content

Module 8, Modules

What is a Module

A module is a directory of Terraform files used together. Every Terraform configuration IS a module (the root module). When you call another module, it becomes a child module.

finpay-infrastructure/
├── main.tf ← root module
├── variables.tf
├── outputs.tf
└── modules/
├── networking/ ← child module
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
└── database/ ← child module
├── main.tf
├── variables.tf
└── outputs.tf

Creating a Module

# modules/s3-bucket/main.tf
resource "aws_s3_bucket" "this" {
bucket = var.bucket_name
tags = var.tags
}

resource "aws_s3_bucket_versioning" "this" {
bucket = aws_s3_bucket.this.id
versioning_configuration {
status = var.versioning_enabled ? "Enabled" : "Disabled"
}
}

# modules/s3-bucket/variables.tf
variable "bucket_name" { type = string }
variable "versioning_enabled" { type = bool; default = true }
variable "tags" { type = map(string); default = {} }

# modules/s3-bucket/outputs.tf
output "bucket_arn" { value = aws_s3_bucket.this.arn }
output "bucket_name" { value = aws_s3_bucket.this.id }

Calling a Module

# root main.tf
module "artifacts_bucket" {
source = "./modules/s3-bucket"

bucket_name = "finpay-artifacts-${var.environment}"
versioning_enabled = true
tags = {
Environment = var.environment
Purpose = "pipeline-artifacts"
}
}

module "logs_bucket" {
source = "./modules/s3-bucket"
bucket_name = "finpay-logs-${var.environment}"
versioning_enabled = false
tags = { Environment = var.environment }
}

# Access module outputs
output "artifacts_arn" {
value = module.artifacts_bucket.bucket_arn
}
tip

Run terraform init after adding any new module source, Terraform needs to download or resolve it.

Public Registry Modules

# Use a community-maintained VPC module from the Terraform Registry
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 5.0"

name = "finpay-vpc"
cidr = "10.0.0.0/16"

azs = ["us-east-1a", "us-east-1b", "us-east-1c"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]

enable_nat_gateway = true
}

Knowledge Check

  1. What command must be run after adding a new module source?
  2. How do you reference an output from a child module in the root config?
  3. What is the difference between source = "./modules/networking" and source = "terraform-aws-modules/vpc/aws"?
  4. True or False: A module can contain other modules.
  5. What is the purpose of module outputs?
  6. Why would you wrap resources in a module even for a solo project?
Exam Mapping
  • HashiCorp Associate Obj 4: Use Terraform outside of core workflow
  • HashiCorp Associate Obj 5: Interact with Terraform modules (10-15% of exam)