Modules Block in Terraform

Last Updated : 30 Apr, 2026

Terraform is an open-source Infrastructure as Code (IaC) tool that allows teams to define and provision infrastructure declaratively across cloud and on-premises environments.

  • A Terraform module is a collection of configurations used to create and manage specific infrastructure components.
  • Modules act as reusable building blocks that promote standardization and reduce duplication.
  • They improve maintainability by organizing infrastructure into modular, scalable structures.
  • Using modules helps teams provision resources more efficiently and follow best practices like the DRY principle.

Defining a Terraform Module

We make a directory containing a collection of Terraform configuration files in order to define a module.

Syntax of the Terraform Module Block

Within your primary Terraform setup, you can call and instantiate modules using the modules block. The syntax is:

module "module_name" {
  source = "path_of_module"
  [other_arguments]
}
  • module_name: The user-defined name for the module instance is module_name.
  • source: This identifies the module's location. A remote module registry (like GitHub or Terraform Registry) or a local file path could both be used.
  • other_arguments: Optional arguments which module can accept as optional arguments.

For example, Let's say we want to set up and provision EC2 instance using a module:

In a different directory, we first define a module called "ec2_instance" with the following structure:

ec2_instance
├── main.tf            # Defines resources
├── variables.tf    # Declares input variables
└── outputs.tf       # Exposes resource outputs
  • main.tf: Contains the core resource definitions required to provision infrastructure.
  • variables.tf: Defines input variables such as instance type or AMI ID, allowing the module to be flexible and reusable.
  • outputs.tf: Specifies the values the module should expose, such as resource IDs or public IP addresses.

By structuring modules this way, teams can standardize deployments and reuse infrastructure components across multiple environments

Now, we can instantiate this module as follows in our main Terraform configuration file:

provider "aws" {
  region = "us-east-2"
}

module "gfg_server" {
  source = "./ec2_instance"

  instance_type = "t2.micro"
  ami_id        = "ami-98656754364"
}

output "instance_id" {
  value = module.gfg_server.instance_id
}
  • The region is set to "us-east-2" and the provider block specifies the AWS provider.
  • The "gfg_server" module is created by the module block. The module found in the "./ec2_instance" directory is referred to.
  • AMI_id is set to "ami-98656754364" and instance_type is set to "t2.micro" inside the module block. The module will use these settings to provision the EC2 instance.
  • A "instance_id" output variable is defined in the output block. The "gfg_server" module is accessed to obtain the instance_id output variable's value.
  • we set the instance_type and ami_id input variables' values inside the module block. To retrieve the output value of the instance_id output variable declared within the module, we lastly use the module.gfg_server.instance_id reference.

Root vs Child Modules

Understanding the difference between root modules and child modules is essential for designing scalable and well-structured Terraform configurations. Terraform organizes infrastructure hierarchically, where one main module acts as the entry point and can call other reusable modules.

Root Module

The root module is the primary working directory where you run Terraform commands such as terraform init, terraform plan, and terraform apply. It typically contains the core configuration files and acts as the orchestrator for your infrastructure.

  • Serves as the entry point for Terraform execution
  • Defines provider configurations and backend settings
  • Passes input variables to child modules
  • Combines multiple modules to build complete infrastructure

Child Modules

A child module is any module that is called by another module (usually the root module). These modules are designed to be reusable and help organize infrastructure into smaller, manageable components.

  • Called using the module block
  • Receives inputs from the root module
  • Returns outputs that can be referenced elsewhere
  • Promotes reusability and standardization

Example: Calling a Child Module from the Root Module

module "vpc" {
  source     = "./modules/vpc"
  vpc_name   = "production-vpc"
  cidr_block = "10.0.0.0/16"
}

How it works:

  • The configuration above is written in the root module.
  • Terraform loads the module from ./modules/vpc.
  • Input variables customize the VPC configuration.
  • Any outputs from the child module can be referenced as:
module.vpc.vpc_id

Fundamentals of Modules

Version

The version attribute can be used to express a module's or provider's version constraint. For

Example:

module "gfg_vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~> 2.0"
  // etc ...
}

In this instance, the "terraform-aws-modules/vpc/aws" module repository is being used to source the module. Versions greater than or equal to 2.0 but are less than 3.0 are allowed, as specified in the version attribute.

Meta-arguments

Let's have a look at the count meta-argument, which enables the creation of many instances of a resource depending on a count value.

resource "aws_instance" "gfg_instances" {
  count = 2
  
  ami           = "ami-3uir3215678"
  instance_type = "t2.micro"
  // etc..
}

By repeatedly iterating over the resource block with the count value of 2, Terraform will in this instance construct two AWS EC2 instances.

Accessing Module Output Values

Let's say you have a module called "app" that generates a DNS name for an application load balancer (ALB) that it creates. You can use the name of the module and the output name in the following format to access this output value in your primary configuration:

module "gfg_app" {
  source = "./modules/app"
  
  // etc..
}

resource "aws_route53_record" "app_dns" {
  zone_id = "ABC123456"
  name    = "gfg-app.example.com"
  // etc..
  records = [module.gfg_app.alb_dns_name]
}

The output value alb_dns_name set in the "app" module is referred to by the module.gfg_app.alb_dns_name. In order to create an AWS Route 53 DNS record, it fetches the ALB's DNS name.

Transferring Resource State Into Modules

Assume you currently handle an AWS S3 bucket outside of Terraform. You can use the terraform import command in the following way to import its state into Terraform

terraform import aws_s3_bucket.gfg_bucket gfg-created-bucket

With the help of this command, the current S3 bucket is linked to the Terraform resource aws_s3_bucket.gfg_bucket, enabling Terraform to control its settings.

Replacing Resources Within a Module

Let's say your "security_group" module controls an AWS security group. You may use the Terraform state mv command to swap out the current security group resource by typing the following

terraform state mv aws_security_group.existing sg.new

The current security group resource aws_security_group.existing is moved in this example using the Terraform command state mv to a new address sg.new. With this alternative, you can modify the resource without affecting the module's other resources.

Benefits of Modules

  • Modules enable reuse of infrastructure code across projects, reducing duplication.
  • Simplify complex setups by providing abstraction.
  • Separate components for better organization and teamwork.
  • Make updates easier and ensure consistent deployments.
Comment