Modules in Terraform Explained with Examples
Modules in Terraform Explained with Examples
Modules in Terraform help reduce code duplication and improve infrastructure consistency.
As your infrastructure grows, managing everything inside a single configuration becomes difficult. Modules provide a cleaner way to organize resources, standardize deployments, and reuse infrastructure components across multiple environments.
Whether you're deploying a single EC2 instance or managing a large cloud platform, modules make Terraform configurations easier to maintain and scale.
What Are Modules in Terraform?
A module is a container for Terraform configuration files that work together to provision infrastructure.
Every Terraform configuration exists inside a module. In fact, whenever you run Terraform commands in a directory, Terraform automatically treats that directory as a module.
This default module is called the root module.
Modules allow you to group related resources into reusable building blocks. Instead of copying the same infrastructure code repeatedly, you can define it once and use it wherever needed.
For example, you might create a module that provisions:
- An EC2 instance
- Security groups
- IAM roles
- Monitoring configuration
That module can then be reused across development, staging, and production environments.
Why Use Modules in Terraform?
When Terraform projects start small, keeping everything in a few .tf files works well.
As infrastructure expands, configurations become harder to manage. You may end up maintaining similar resource definitions across multiple environments and projects.
Common challenges include:
- Repeated infrastructure code
- Increased maintenance effort
- Configuration drift between environments
- Higher risk of deployment mistakes
Imagine maintaining separate EC2, IAM, and networking resources for development, staging, and production. A simple change may require updating several files in multiple locations.
Modules solve this by centralizing infrastructure logic and making it reusable.
Real-World Example
Many DevOps teams create a single EC2 module and reuse it across multiple environments. Instead of maintaining separate EC2 resource definitions, they simply pass different AMI IDs, instance types, tags, and networking settings through variables.
Root Modules vs Child Modules Explained
The directory where Terraform commands are executed is known as the root module.
Any module referenced from the root module becomes a child module.
A child module can be stored:
- Locally on your machine
- In a Git repository
- In an object storage location
- In the Terraform Registry
If you want to learn how publicly available modules work, check out our guide on using modules from the Terraform Registry.
How to Create and Use a Local Terraform Module
This is the same approach commonly used by platform engineering and DevOps teams to standardize infrastructure deployments.
A module may be reused dozens of times with different variable values while keeping the underlying infrastructure definition identical.
Step 1: Create a Child Module
Create a directory that contains the resources you want to reuse.
A typical module structure looks like this:
modules/
└── ec2/
├── main.tf
├── variables.tf
└── outputs.tf
Example main.tf:
resource "aws_instance" "web" {
ami = var.ami
instance_type = var.instance_type
key_name = var.key_name
}
The variables.tf file defines the inputs accepted by the module.
If you're new to variables, read our guide on Terraform input variables.
Step 2: Call the Module from the Root Module
Now create another directory that acts as the root module.
terraform-project/
├── modules/
│ └── ec2/
└── development/
└── main.tf
Inside development/main.tf:
module "dev_web_server" {
source = "../modules/ec2"
ami = "ami-0abcd1234efgh5678"
instance_type = "t2.micro"
key_name = "dev-key"
}
Terraform will load the configuration from the child module and provision resources using the values provided.
If you want a complete walkthrough, see our guide on creating and using Terraform modules.
Understanding the Terraform Module Block
A module is referenced using the module block.
Example:
module "web_server" {
source = "../modules/ec2"
ami = "ami-0abcd1234efgh5678"
instance_type = "t2.micro"
}
Key components include:
- module "web_server" – Logical name used within the configuration
- source – Location of the module
- Input arguments – Values passed into the module
The source attribute is required and tells Terraform where to find the module.
Pro Tip
Avoid creating large modules that deploy unrelated infrastructure together. Smaller, focused modules are easier to test, maintain, version, and reuse.
Module Sources in Terraform
Terraform supports multiple module sources.
Local Modules
Stored within the same repository.
source = "../modules/ec2"
Git Repositories
Stored in a version control system.
source = "git::https://github.com/example/terraform-modules.git//ec2"
Terraform Registry
The official Terraform Registry contains thousands of community and vendor-maintained modules.
Example:
source = "terraform-aws-modules/vpc/aws"
Versioned Modules
For production environments, always pin module versions.
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 5.0"
}
Version pinning helps prevent unexpected infrastructure changes.
You can learn more about version management in our guide on Terraform version constraints.
Module Inputs and Outputs
Modules become reusable because they accept inputs and expose outputs.
Inputs
Inputs allow consumers to customize module behavior.
Example:
variable "instance_type" {
type = string
}
Inputs are commonly defined in variables.tf.
Related reading:
Outputs
Outputs expose values from a module to other configurations.
Example:
output "instance_id" {
value = aws_instance.web.id
}
Outputs are typically stored in outputs.tf.
To learn more, see our guide on Terraform output variables.
Benefits of Using Modules in Terraform
Improved Reusability
Define infrastructure once and reuse it across multiple projects and environments.
Better Collaboration
Teams can work independently on modules without modifying unrelated infrastructure code.
Easier Maintenance
A change made inside a module can be applied consistently wherever the module is used.
Standardized Infrastructure
Modules help enforce organizational standards and reduce configuration drift.
Faster Development
Engineers spend less time rewriting infrastructure code and more time delivering features.
Best Practices for Terraform Modules
Follow these practices when building production-ready modules:
- Keep modules focused on a single responsibility.
- Use meaningful variable names.
- Document inputs, outputs, and examples.
- Store modules in version control.
- Pin module versions in production.
- Avoid hardcoding environment-specific values.
- Use outputs to expose only necessary information.
- Include a README file for every shared module.
- Test modules before publishing them for reuse.
For larger Terraform projects, combine modules with Terraform workspaces and remote state and state locking to improve collaboration and state management.
Common Mistakes When Using Terraform Modules
Creating Large Monolithic Modules
Modules that manage unrelated resources become difficult to maintain.
Keep modules focused on a specific purpose.
Hardcoding Values
Avoid embedding environment-specific values directly inside modules.
Use variables instead.
Ignoring Versioning
Without version constraints, infrastructure changes can become unpredictable.
Poor Documentation
Undocumented modules are difficult for other engineers to adopt and maintain.
Frequently Asked Questions (FAQ)
What is a module in Terraform?
A module is a collection of Terraform configuration files that work together to provision infrastructure and can be reused across multiple projects.
What is the difference between a root module and a child module?
The root module is the directory where Terraform commands are executed. Any module referenced from that configuration is considered a child module.
Can I use modules from a Git repository?
Yes. Terraform supports modules hosted in Git repositories, including GitHub, GitLab, Bitbucket, and other Git-compatible platforms.
What is the Terraform Registry?
The Terraform Registry is the official repository for sharing and discovering Terraform modules and providers.
Do I need variables in every module?
No. Variables are only required when a module needs input values from consumers.
Can a Terraform module call another module?
Yes. Child modules can reference additional child modules, creating nested module structures when needed.
Should I version Terraform modules?
Yes. Versioning is a best practice for production environments because it helps ensure predictable deployments and controlled upgrades.
Final Thoughts
Most real-world Terraform deployments rely heavily on modules.
They reduce duplication, improve consistency, and make infrastructure easier to maintain as environments grow. Once you start organizing infrastructure into reusable modules, managing large Terraform codebases becomes significantly simpler.
Whether you're deploying AWS resources, Kubernetes infrastructure, or multi-cloud environments, modules are one of the most important Terraform concepts to master.
8 free, 100% client-side tools for developers — no signup, no data uploads.
Explore all tools