Contents
What is a Terraform module?
A Terraform module is a set of Terraform configuration files in a single directory. Even a simple configuration consisting of a single directory with one or more .tf files is a module. When you run Terraform commands directly from such a directory, it is considered the root module. So in this sense, every Terraform configuration is part of a module. You may have a simple set of Terraform configuration files such as:
.
├── LICENSE
├── README.md
├── main.tf
├── variables.tf
├── outputs.tf
In this case, when you run terraform commands from within the minimal-module directory, the contents of that directory are considered the root module.
Understand how modules work
When using a new module for the first time, you must run either terraform init or terraform get to install the module. When you run these commands, Terraform will install any new modules in the .terraform/modules directory within your configuration’s working directory. For local modules, Terraform will create a symlink to the module’s directory. Because of this, any changes to local modules will be effective immediately, without having to reinitialize or re-run terraform get.
After following this tutorial, your .terraform/modules directory will look like the following.
.terraform/modules/
├── ec2_instances
├── modules.json
└── vpc
Configuration model
A module block supports the following configuration:
module "<LABEL>"— block- module-specific inputs — some inputs may be required
source— string | requiredversion— stringcount— number | mutually exclusive withfor_eachdepends_on— list of referencesfor_each— map or set of strings | mutually exclusive withcountproviders— map
Complete configuration
The following module block includes all built-in arguments:
module "<LABEL>" {
<module-specific-inputs>
source = "<location-of-module-sources>"
version = "<constraint>" # only available for modules listed in a registry
count = <number> # mutually exclusive with `for_each`
for_each = { # mutually exclusive with `count`
<KEY> = <VALUE>
}
for_each = [ # `for_each` accepts a map or a set of strings
"<VALUE>",
"<VALUE>"
]
providers = {
"<provider-name-in-child-module>" = "<provider-name-from-parent-module>"
}
depends_on = [ <resource.address.reference> ]
}Standard module structure
A minimal recommended module following the standard structure is shown below. While the root module is the only required element, we recommend the structure below as the minimum:
$ tree minimal-module/
.
├── README.md
├── main.tf
├── variables.tf
├── outputs.tf
A complete example of a module following the standard structure is shown below. This example includes all optional elements and is therefore the most complex a module can become:
$ tree complete-module/
.
├── README.md
├── main.tf
├── variables.tf
├── outputs.tf
├── ...
├── modules/
│ ├── nestedA/
│ │ ├── README.md
│ │ ├── variables.tf
│ │ ├── main.tf
│ │ ├── outputs.tf
│ ├── nestedB/
│ ├── .../
├── examples/
│ ├── exampleA/
│ │ ├── main.tf
│ ├── exampleB/
│ ├── .../