Modules & Reusability
Modules are self-contained, versionable packages of configuration. Learn to build child modules with clean variable/output interfaces, source them from the registry or git, and reuse infrastructure safely.
What is this?
A module is a directory of .tf files with its own variables, resources and outputs. Every Terraform configuration is a module — the one you run is the root module. A module block calls a child module by source and passes variables; the child module publishes outputs back to the caller. Modules are the standard mechanism for reuse, sharing and versioning infrastructure.
Why do you need it?
- Encapsulate a reusable stack (VPC, EKS cluster, IAM roles) behind a clean interface.
- Versioning: pin a module to a tag or semver and upgrade deliberately.
- Standardization: org-wide patterns replace copy-pasted config that drifts apart.
- Small blast radius: fix a bug once in the module, then roll it out everywhere.
Mental model
A library of functions in code
Terraform modules
You call a function with arguments and get a return value without reading its internals. You call a module with variables and read its outputs without understanding every resource inside it.
How it works
- The root module is the directory where you run Terraform; any other module it calls is a child module.
- A module block declares the call, for example module "vpc" { source = "./modules/vpc" ... }.
- The child module's variable blocks define its inputs; output blocks define its results.
- Sources can be local paths, git URLs, the public registry or a private registry.
- Terraform merges everything into one dependency graph; module resources are addressed as module.vpc.<resource>.
- Registry modules are versioned so infrastructure is reproducible across teams and time.
Root module composing child modules.
Key commands
terraform initDownload module sources referenced by the configuration.
terraform getFetch and update modules from their sources.
terraform get -updateRe-download modules, ignoring cached copies.
terraform providersShow provider requirements aggregated across all modules.
terraform state listList resources including module addresses like module.vpc.aws_vpc.main.
terraform validateValidate the full configuration including module interfaces.
Examples
A reusable IAM user module
# modules/iam_user/main.tfvariable "user_name" { type = string} resource "aws_iam_user" "this" { name = var.user_name} output "arn" { value = aws_iam_user.this.arn} # main.tf (root module)module "deploy_user" { source = "./modules/iam_user" user_name = "deploy-bot"} output "deploy_arn" { value = module.deploy_user.arn}The child module takes one input (user_name), creates the IAM user, and exposes its ARN as an output. The root module calls it with a source path and reads the result via module.deploy_user.arn.
In production
- Publish internal, compliance-approved modules to a private registry or Terraform Cloud.
- Compose environment stacks from small, single-purpose modules instead of one giant config.
- Pin modules to versions (exact or ~> ranges) and test upgrades in a staging workspace first.
- Standardize tagging, encryption and logging policy inside shared modules.
Best practices
- Keep modules small and single-purpose: one module per concern.
- Document every input and output; give every variable a sensible default.
- Version remote modules explicitly; never float on the source branch HEAD.
- Keep the root module thin — it should glue modules together, not contain logic.
- Avoid module-to-module coupling; pass values through root-level outputs.
Common mistakes
- Building monolithic modules that are hard to review, test and version.
- Referencing child module resources directly instead of declaring outputs.
- Not versioning remote modules, so deployments become unreproducible.
- Passing secrets through plain variables into modules.
Common issues
Error: Module source ... failed to downloadWrong source path/URL or missing git credentials for remote sources.
Verify the source path or URL, and confirm credentials work before running terraform get.
Error: module "vpc": no outputs definedThe child module has no output blocks, so nothing can be referenced.
Add output blocks to the child module and run terraform plan again.
Error: Unsupported block type: "module"The Terraform version is too old to support the module syntax used.
Upgrade Terraform or rewrite the module call to a compatible syntax.
Debugging tips
- terraform get -update forces fresh module downloads when a source changed.
- terraform providers reveals which provider versions each module requires.
- terraform state list shows how modules are addressed in state, with module. prefixes.
- terraform console can evaluate module.<name>.<output> references for debugging.
Interview checkpoint
Hands-on lab
- Create a child module with inputs and outputs
- Call it from a root module
- Reuse the same module twice with different inputs
- Use for_each to scale module usage
Build and Call a Reusable Module
35 min · intermediate
Quick quiz
Which block type is used to call a child module?
How does the root module access a value produced inside a child module?
A module can be sourced from git, a local path, or a registry.
Cheat sheet
module "vpc" { source = "./modules/vpc" }Call a local child modulesource = "git::https://github.com/org/vpc.git?ref=v2.1.0"Git source with tagsource = "app.terraform.io/org/vpc/aws"Private registry sourceterraform get -updateRefresh module sourcesmodule.vpc.vpc_idReference a module output