Day 35: Mastering Terraform Modules
Jun 22, 2025
•01:38 AM GMT+8

When you have Terraform projects on multiple resources or environments, repeating configurations can become inefficient and difficult to manage. This problem is solved by Terraform modules, which offer encapsulation and reuse of configurations. Using modules keeps your code clean and maintainable (DRY, Don't Repeat Yourself).
Understanding Module
What is a module in Terraform?
A module is a collection of .tf
files grouped together to perform a specific function or define a particular set of infrastructure components. Terraform configurations set in folders can be considered modules in their simplest form.
There are two main types of modules:
- Root module: The main configuration directory where you run
terraform init
,plan
, andapply
. - Child module: A module called from the root module or another module.
Why use modules?
Modules promote:
- Reusability: Define a component once and use it multiple times.
- Consistency: Enforce standards across environments.
- Maintainability: Easier to update or fix issues in one place.
- Collaboration: Enable teams to work on smaller, focused parts of infrastructure.
Understanding Child and Parent Modules in Terraform
A parent module is containers for multiple resources that are used together. The child module is simply any module that is called by another configuration.

💡Note: Outputs from modules are not automatically visible in the parent configuration. You must explicitly define outputs in the child module and reference them from the parent module.
What is a module made of?
In Terraform module, configuration .tf
files are organized into dedicated directories.
It is similar on this example directory structure below:
├── modules
| └── module_1
| ├── main.tf
| ├── variables.tf
| └── outputs.tf
└── main.tf
A Terraform module usually consist of:
main.tf
: This is where you defines all the infrastructure resources (like virtual machines or databases) and data sources (for fetching information about existing infrastructure) that the module will manage or interact with.variables.tf
: Declares the input variables that the module accepts from its calling configuration (the parent module or root module).outputs.tf
: Defines the output values that the module will expose to its parent module or to the user.providers.tf
(Optional but recommended): specifies the providers (e.g., aws, azurerm, google) that the module relies on.
Task
Let's now create and apply a Terraform configuration that uses modules. This task will guide you through a simple configuration into reusable module for better structure and scalability.
Step 1: Clone the Repository
Start by cloning the sample repository and navigate to the module directory.
git clone https://github.com/git-adrianrubico/learn-terraform
cd learn-terraform/07-Module
Step 2: Review the Existing Module Folder
Here are the following files of the resource group module:
resource_group/main.tf
resource "azurerm_resource_group" "rg-example" {
name = var.rgname
location = var.azregion
tags = {
environment = local.env
}
}
resource_group/variables.tf
variable "rgname" {
default = "Name of Resource Group"
type = string
}
variable "azregion" {
description = "Location of Region"
type = string
default = "EAST US"
}
resource_group/outputs.tf
The purpose of this file is to expose values for use in other modules.
output "resouce_group_name" {
value = azurerm_resource_group.rg-example.name
}
output "resource_group_location" {
value = azurerm_resource_group.rg-example.location
}
output "resource_group_tag_env" {
value = azurerm_resource_group.rg-example.tags
}
And here are the following files for the root module:
main.tf
As you can see, we can override the region even if a default region is specified in the resource group module's variables.
module "resource_group" {
source = "./resource_group"
rgname = "rg-module-example"
azregion = "JAPAN EAST"
}
outputs.tf
output "resource_group_name" {
value = module.resource_group.resouce_group_name
}
output "resouce_group_location" {
value = module.resource_group.resource_group_location
}
output "resource_group_tag_env" {
value = module.resource_group.resource_group_tag_env
}
Step 3: Initialize and Apply the Resource Group module
Apply to the infrastructure:
terraform init
terraform plan
terraform apply

Verify in the Azure Portal:

Step 4: Create New Module for Storage Account
Create a new folder named storage_account
and add the following .tf
files:
storage_account/main.tf
resource "azurerm_storage_account" "sa-example" {
name = var.stgname
resource_group_name = var.rgname
location = var.rgloc
account_tier = var.acctier
account_replication_type = var.reptype
tags = {
environment = var.tag
}
}
storage_account/variables.tf
variable "stgname" {
type = string
description = "Name of Storage Account"
}
variable "rgname" {
type = string
description = "Name of Resource Group"
}
variable "rgloc" {
type = string
description = "Resource Group Location"
}
variable "acctier" {
type = string
description = "Storage Account Tier"
}
variable "reptype" {
type = string
description = "Storage Account Replication Type"
}
variable "tag" {
type = map(string)
description = "Tag Name"
}
storage_account/outputs.tf
output "storage_account_name" {
value = azurerm_storage_account.sa-example.name
}
Step 5: Modify the main.tf
from root module
Add storage_account
module references:
module "storage_account" {
source = "./storage_account"
stgname = "stgmoduletest01"
rgname = module.resource_group.resouce_group_name
rgloc = module.resource_group.resource_group_location
acctier = "Standard"
reptype = "LRS"
tag = module.resource_group.resource_group_tag_env
}
Step 6: Update outputs.tf from root module
output "storage_account_name" {
value = module.storage_account.storage_account_name
}
Step 7: Initialize and Apply
Before applying changes, run:
terraform init

This step reinitialized Terraform, downloading and preparing the modules you defined. It is required when you introduce new modules or change sources.
Then, proceed to:
terraform plan
terraform apply
Step 8: Verify the created Storage Account in Azure Portal

Conclusion
In this blog, we explored the fundamentals of Terraform modules. We learned how to separate configuration into reusable components by creating resource group a storage account module. This approach helps organize Terraform code, improve maintainability, and promote reuse across environments.
We also covered how to pass variables and expose outputs between child and parent modules. Understanding how to structure and reference modules is a key step in writing scalable and production-ready infrastructure code.
In the next blog, we will dive into Terraform Backends to understand how to manage and secure the state file remotely and support team collaboration.
Day 35: Mastering Terraform Modules
Learn how to create and use reusable Terraform modules for cleaner, scalable, and organized infrastructure as code projects.
For the passion of automated cloud solutions.
Subscribe to get the latest posts. I mostly write about Backend (Python/Bash), DevOps and Linux.