Terraform Tutorial · Modules and Quality · Lesson 21 of 25

Terraform Modules

Modules package configuration for reuse. Learn to write a module with inputs and outputs, call it, version it, and use modules from the Terraform Registry.

What is a module?

Every directory of .tf files is a module. The one you run terraform in is the root module; modules it calls are child modules. A module is like a function: variables are its inputs, outputs its return values.

A module with inputs and an output
# file: main.tf
module "naming" {
  source      = "./modules/naming"
  project     = "shop"
  environment = "prod"
}

output "bucket_name" {
  value = module.naming.bucket_name
}
# file: modules/naming/main.tf
variable "project" {
  type = string
}

variable "environment" {
  type = string
}

output "bucket_name" {
  value = "${var.project}-${var.environment}-assets"
}

Output

bucket_name = "shop-prod-assets"

Run this on your computer — see “Get Started” for setup.

Calling a module

module "network" {
  source = "./modules/network"     # a local path

  cidr_block  = "10.0.0.0/16"
  environment = var.environment
}

resource "aws_instance" "app" {
  subnet_id = module.network.private_subnet_ids[0]
  # ...
}

Registry and Git modules

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~> 6.0"
  # ...
}

module "tagging" {
  source = "git::https://github.com/acme/tf-modules.git//tagging?ref=v1.4.0"
}

Always pin a version (version for registry modules, ?ref= for Git) so upgrades are deliberate.

Good module design

  • One clear job (a network, a database, a service), not "everything".
  • Few, well-described variables with sensible defaults and validation.
  • Outputs for everything a caller might need.
  • No provider blocks inside reusable modules: let the caller configure providers.

Test yourself

How do you read output vpc_id from a module named network?

  1. network.vpc_id
  2. module.network.vpc_id
  3. output.network.vpc_id
  4. var.network.vpc_id
Show answer

Answer: module.network.vpc_id