Terraform
Intermediate 16 min read Terraform

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.

moduleschild moduleroot modulemodule registrysourceversioningfor_each
Introduction

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.

Motivation

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.
Think about it

Mental model

Imagine

A library of functions in code

Think of

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.

Mechanics

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.

Root module
module "vpc"
module "eks"
module "app"
Outputs
Reference

Key commands

terraform init

Download module sources referenced by the configuration.

terraform get

Fetch and update modules from their sources.

terraform get -update

Re-download modules, ignoring cached copies.

terraform providers

Show provider requirements aggregated across all modules.

terraform state list

List resources including module addresses like module.vpc.aws_vpc.main.

terraform validate

Validate the full configuration including module interfaces.

Hands-on

Examples

A reusable IAM user module

A reusable IAM user module
# modules/iam_user/main.tf
variable "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.

Real world

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.
Guidelines

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.
Watch out

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.
Root cause analysis

Common issues

Error
Error: Module source ... failed to download
Root cause

Wrong source path/URL or missing git credentials for remote sources.

Fix

Verify the source path or URL, and confirm credentials work before running terraform get.

Error
Error: module "vpc": no outputs defined
Root cause

The child module has no output blocks, so nothing can be referenced.

Fix

Add output blocks to the child module and run terraform plan again.

Error
Error: Unsupported block type: "module"
Root cause

The Terraform version is too old to support the module syntax used.

Fix

Upgrade Terraform or rewrite the module call to a compatible syntax.

When things break

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.
Interviews

Interview checkpoint

Practice

Hands-on lab

Build and Call a Reusable Module
35 min · intermediate
In progress
Objectives
  • 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

0/5 steps
0%
sandbox · Linux sandbox
$
Try these commands
Test yourself

Quick quiz

0/3
1

Which block type is used to call a child module?

2

How does the root module access a value produced inside a child module?

3

A module can be sourced from git, a local path, or a registry.

Quick reference

Cheat sheet

Module usage
module "vpc" { source = "./modules/vpc" }Call a local child module
source = "git::https://github.com/org/vpc.git?ref=v2.1.0"Git source with tag
source = "app.terraform.io/org/vpc/aws"Private registry source
terraform get -updateRefresh module sources
module.vpc.vpc_idReference a module output
Go deeper

Official documentation