Creating and Using a Module in Terraform
Creating and using a module in Terraform is one of the most effective ways to manage infrastructure at scale. Instead of copying the same resource definitions across multiple projects, you can package infrastructure into reusable building blocks and deploy them consistently across environments.
As Terraform projects grow, modules become essential for keeping configurations organized, reducing duplication, and making infrastructure easier to maintain. Whether you're deploying applications across multiple AWS regions or standardizing infrastructure across development, staging, and production environments, modules help keep everything predictable.
Before creating custom modules, it's helpful to understand the fundamentals of Terraform modules and how Terraform uses root and child modules.
What Is a Terraform Module and How Does It Work?
A Terraform module is a collection of Terraform configuration files stored in a directory. Every Terraform configuration has at least one module.
Terraform organizes modules into two categories:
- Root Module – The directory where Terraform commands are executed.
- Child Module – Any module that is called by another module.
Modules allow you to:
- Organize complex infrastructure into logical components
- Reuse code across multiple environments
- Standardize deployments across teams
- Reduce configuration drift
- Simplify maintenance and upgrades
According to the official Terraform documentation, modules are the primary mechanism for code reuse and organization within Terraform configurations.
Why Terraform Modules Are Essential for Reusable Infrastructure
Infrastructure often starts small. A few resources become dozens, then hundreds.
Imagine managing separate Terraform configurations for ten AWS regions. A simple EC2 configuration change would require updates in every location. That approach quickly becomes difficult to maintain and increases the risk of inconsistent deployments.
Creating and using a module in Terraform solves this problem by allowing you to define infrastructure once and reuse it wherever needed.
For example, a module can contain:
- An EC2 instance
- An S3 bucket
- A DynamoDB table
- Security groups
- IAM roles
Instead of recreating these resources repeatedly, you call the same module and provide different inputs.
Pro Tip: Keep modules focused on a single responsibility. Create separate modules for networking, compute, storage, databases, and monitoring rather than building one large module that provisions everything.
How to Design a Reusable Terraform Module
Let's consider a fictional company called Flex IT Consulting.
The company needs to deploy its payroll application in multiple countries while maintaining the same architecture everywhere.
Each deployment requires:
- An EC2 instance for the application
- A DynamoDB table for payroll records
- An S3 bucket for storing documents
The reusable module is stored in the following directory:
/root/terraform-projects/modules/payroll-app/
The module contains Terraform configuration files that define:
- An EC2 instance with a configurable AMI
- A DynamoDB table
- An S3 bucket with a unique regional prefix
The EC2 deployment approach is similar to the process explained in deploying EC2 instances with Terraform.
Some values remain fixed to enforce organizational standards, while others are exposed as variables to support different deployment scenarios.
Example: Defining Input Variables for Flexibility
Input variables allow modules to accept different values without modifying the module itself.
If you're new to variables, review this guide on Terraform input variables.
Example:
variable "app_region" {
type = string
}
variable "ami" {
type = string
}
variable "bucket" {
type = string
default = "flexit-payroll-alpha-22001c"
}
These variables can be referenced throughout the module to customize deployments.
Common Mistake: Avoid hardcoding AMI IDs inside modules. AMIs change frequently, and exposing them as variables makes upgrades and maintenance much easier.
Terraform Module Directory Structure
A common Terraform module structure looks like this:
modules/
└── payroll-app/
├── main.tf
├── variables.tf
├── outputs.tf
└── versions.tf
Each file serves a specific purpose:
main.tfdefines resources.variables.tfdeclares input variables.outputs.tfexposes values to callers.versions.tfdefines Terraform and provider version requirements.
This structure keeps modules easy to understand and maintain.
How to Call a Terraform Module from the Root Module
To deploy the payroll application in the US East region, create a root module directory:
/root/terraform-projects/us-payroll-app/
Inside main.tf:
module "us_payroll" {
source = "../modules/payroll-app"
app_region = "us-east-1"
ami = "ami-1234567890abcdef0"
}
The source argument tells Terraform where the module is located.
You can override optional variables when necessary while preserving the module's standardized architecture.
While this guide focuses on custom modules, you can also learn about using modules from the Terraform Registry to accelerate infrastructure deployment.
You can browse publicly available modules on the official Terraform Registry.
Creating and Using a Module in Terraform Across Multiple Regions
One of the biggest advantages of modules is multi-region deployment.
Suppose Flex IT Consulting wants to deploy the same payroll application in the UK.
Create another root module directory:
/root/terraform-projects/uk-payroll-app/
Then define the module:
module "uk_payroll" {
source = "../modules/payroll-app"
app_region = "eu-west-2"
ami = "ami-0987654321fedcba0"
}
The infrastructure architecture remains identical while deployment-specific values change.
This pattern is commonly used by organizations that deploy applications across multiple AWS regions for:
- Reduced latency
- Regulatory compliance
- Disaster recovery
- High availability
After configuration, run:
terraform init
terraform plan
terraform apply
If you are new to these commands, review our complete guide on Terraform commands explained.
Understanding Module Resource Addresses in Terraform
When Terraform creates resources through modules, it assigns fully qualified resource addresses.
The format is:
module.<module_name>.<resource_type>.<resource_name>
Example:
module.us_payroll.aws_dynamodb_table.payroll_db
Terraform uses these addresses for:
- State management
- Resource targeting
- Import operations
- Debugging
Debugging Tip: Run the following command to see all resources tracked in Terraform state:
terraform state list
For a deeper understanding of how Terraform tracks resources, see our guides on purpose of state in Terraform and introduction to Terraform state.
Benefits of Creating and Using a Module in Terraform
Using modules provides several long-term advantages.
Simplifies Configuration
A single module replaces repeated resource definitions across multiple projects.
Enhances Reusability
The same module can be used in development, staging, production, and disaster recovery environments.
Improves Consistency
Teams follow the same infrastructure standards across all deployments.
Reduces Maintenance
Changes are made once within the module and automatically applied wherever the module is used.
Supports Team Collaboration
Modules establish reusable patterns that allow multiple engineers to work efficiently without duplicating infrastructure code.
Best Practices for Terraform Modules
When creating modules, follow these recommendations:
- Keep modules small and focused.
- Expose only necessary variables.
- Use meaningful variable descriptions.
- Document inputs and outputs.
- Avoid embedding environment-specific values.
- Version modules when sharing them across teams.
- Pin provider versions using Terraform version constraints.
- Store modules in source control systems such as Git.
For provider version management, see our guide on version constraints in Terraform.
Conclusion
Creating and using a module in Terraform helps transform infrastructure code from repetitive configurations into reusable, maintainable building blocks.
As infrastructure grows, modules make it easier to standardize deployments, reduce operational overhead, and improve collaboration across engineering teams.
Whether you're deploying a simple application or managing infrastructure across multiple regions, modules provide a scalable foundation for long-term Terraform success.
Frequently Asked Questions (FAQs)
What is a Terraform module?
A Terraform module is a reusable collection of Terraform configuration files that can define one or more resources and be called from other Terraform configurations.
How is a module different from a resource?
A resource represents a single infrastructure component such as an EC2 instance or S3 bucket. A module groups multiple resources together into a reusable unit.
Can modules be version controlled?
Yes. Modules can be stored in Git repositories, private registries, or the Terraform Registry. Versioning helps teams manage updates safely and predictably.
Can I override default values in a module?
Yes. Any input variable with a default value can be overridden from the calling module block.
Are modules mandatory in Terraform?
No. Small projects can work without modules. However, modules are strongly recommended for medium and large infrastructure deployments because they reduce duplication and improve maintainability.
What is the difference between a custom module and a Registry module?
A custom module is built and maintained by your organization. A Registry module is published through the Terraform Registry and can be reused directly by referencing its source and version.
8 free, 100% client-side tools for developers — no signup, no data uploads.
Explore all tools