Terraform modules are a powerful way to structure and manage infrastructure as code, enabling reusability, consistency, and scalability across projects. In this FAQ, we'll cover common questions about Terraform modules, including their purpose, best practices, and how to use them effectively in real-world scenarios.
Introduction to Terraform Modules:
Structure and Organization of Terraform Modules:
Creating and Managing Terraform Modules:
See the FAQ Part 2 for the most common questions about versioning and troubleshooting of Terraform modules.
Terraform modules are reusable code blocks similar in concept to subroutines in traditional programming languages. Modules are widely used to standardize infrastructure deployment and simplify complex configurations.
A Terraform module is a collection of Terraform configuration files organized in a directory.
The files form a reusable unit of infrastructure code that defines a resource or a group of related resources.
A module can be as simple as a single .tf
file or can contain multiple files with many resource
definitions, variables, and outputs.
Typically, a module consists of the following files:
main.tf
- contains the core resources and logic.variables.tf
- declares input variables to make the module configurable.outputs.tf
- defines output values that other configurations can use.
Here is an example of a Terraform configuration with a module called vpc
:
The tf-project/
folder (root module) contains two files - variables.tf
and main.tf
with the following content:
This configuration utilizes Google GCP provider and calls the vpc
module to provision a virtual
private cloud (VPC) network with the name my-vpc
.
The module
block specifies the location of the module files (source
) and defines the VPC
configuration parameters - vpc_name
and project_id
.
The vpc
module creates an auto mode VPC network ("google_compute_network"
) with the name
and location defined by the two input variables - vpc_name
and project_id
.
The module consists of three files - variables.tf
, main.tf
, and outputs.tf
located in the modules/vpc/
folder:
A Terraform configuration is any set of .tf
files that define infrastructure.
Terraform configurations may or may not use modules.
A Terraform module is a specific type of configuration that is reusable and can be called from another module or configuration.
The Terraform configuration files placed directly within a project folder (excluding any sub-folders) form the root module. The root module may utilize other explicitly defined modules stored, for instance, in sub-folders under the main project directory. Such structure helps divide infrastructure into smaller, easier to manage reusable components.
Let's review the following folder structure as an example:
my-app/
folder.my-app/
folder -
main.tf
, variables.tf
, and backend.tf
.vpc/
and vm/
.Using Terraform modules offers several benefits:
By leveraging modules, teams can keep Terraform configurations organized, scalable, and easy to manage.
A well-structured Terraform module typically follows this layout:
Such structure makes it easier to navigate, reuse, and maintain modules.
Consistent naming conventions improve readability and usability. Follow these guidelines:
aws-vpc
or gcp-network
.instance_type
instead of instanceType
.web_server
.
Use nouns for resource names and do not include the resource type in the name.vpc_id
or db_endpoint
.Adhering to these conventions ensures clarity and consistency across Terraform configurations.
Yes, Terraform allows nested modules, meaning one module can contain another modules inside it. This can be useful for organizing complex infrastructure by keeping all related resources together.
In the example below, the network module includes separate submodules for VPC, subnet, and security group:
Best practices for using nested modules:
To ensure Terraform modules are easy to use, maintain, and scale, follow these best practices:
main.tf
(resources) file,
variables.tf
(inputs), outputs.tf
(outputs), and optionally a
README.md
file for documentation.README.md
file with usage instructions, variable descriptions, and example
configurations.
Input variables allow modules to be flexible and customizable.
The variable
blocks withing a module define the module's configurable parameters.
The calling module uses these variables to pass the desired values to the module.
Let'a review this example of a module that provisions an Ubuntu VM in GCP:
The vm
module has five input parameters - two optional and three mandatory.
The mandatory parameters (vm_name
, project_id
, and zone_name
) do not have default
values and must be explicitly defined when invoking the module.
The calling module may also set values the optional parameters (vm_type
and network_name
) to override
the defaults.
Here is an example of module invocation that overrides the default network_name
value:
Some best practices for using input variables:
validation
block) to check whether input values are formatted properly.ephemeral
and sensitive
if necessary.README.md
for better usability.Output values allow a module to expose resource attributes so they can be used by other modules or configurations.
The following code fragments illustrate how to pass information from one module to another.
The configuration shown below employs two modules - vpc
and vm
to provision a VM attached
to a VPC network.
First, it calls the vpc
module to create a network. After completion, the vpc
module returns
a reference to the newly created VPC network in the vpc_self_link
output variable.
Then, the configuration invokes the vm
module and supplies network details by referencing the output from
the first module with the module.vpc.vpc_self_link
construct, where vpc
indicates the module
name and vpc_self_link
- the output name.
Here is the code for the vpc
module that provisions a network and returns its self link reference in the output
variable called vpc_self_link
.
Note: Terraform does not displays the outputs from modules. To show the values, add output
blocks in the root
module.
Best practices for using module outputs:
sensitive = true
to prevent logging.README.md
.Locals allow you to:
The following example shows a locals
block used to construct a firewall rule description with
a heredoc string. The resulting string is later referenced in the google_compute_firewall
block
as local.description
keeping the module's code easy readable and concise.
In this post we reviewed some of the most often asked questions about Terraform modules organization and structure. In the Part 2 we cover more advanced topics of module versioning and utilization of code repositories for hosting Terraform modules.
See Also:
Handling Terraform State in Multi-Environment Deployments
Understanding Terraform Variable Precedence
Terraform Value Types Tutorial
Terraform count
Explained with Practical Examples
Terraform for_each
Tutorial with Practical Examples
Exploring Terraform dynamic
Blocks with GCP Examples
Working with External Data in Terraform
Handling Sensitive and Ephemeral Data in Terraform