Terraform Modules · Topic 2 of 2

Using Modules and Managing Versions

Terraform Associate 004: calling modules with inputs, count and for_each, standard module structure, version constraints and upgrading with terraform init.

  • 5 min
In a nutshell
  • A module block needs source; other arguments set the child's input variables.
  • Modules support count, for_each, depends_on and providers.
  • Read outputs as module.NAME.OUTPUT, or module.NAME["key"].OUTPUT for for_each instances.

What it is

Using a module means calling it from a module block, passing it input values and reading its outputs. A module lets you package a set of resources once and reuse it across projects and environments.

Managing module versions means pinning the module code your configuration accepts, so an upstream change cannot alter your infrastructure without your approval.

module blocksource and versionterraform initinstalls allowed versionInputsargumentsOutputsmodule.NAME.attr

How it works

Calling a module

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~> 5.0"

  name = "main"
  cidr = "10.0.0.0/16"
}

source and version are read by Terraform itself; name and cidr set the module's input variables. Each output of the module is available as module.vpc.OUTPUT_NAME.

Module blocks also accept the meta-arguments count, for_each, depends_on and providers, listed with the two Terraform arguments below.

ArgumentUse in a module block
sourceWhere the module code comes from (required)
versionAccepted versions, registry modules only
count / for_eachCreate several instances of the module
depends_onExplicit dependency for the whole module
providersPass specific provider configurations to the child

Several instances with for_each

module "bucket" {
  source   = "./modules/bucket"
  for_each = toset(["logs", "assets"])
  name     = each.key
}

Each instance has its own address, such as module.bucket["logs"], and outputs are read as module.bucket["logs"].arn.

Standard module structure

HashiCorp recommends a standard layout for reusable modules.

File or folderContents
main.tfThe main resources
variables.tfInput variable declarations
outputs.tfOutput declarations
README.mdWhat the module does and how to use it
LICENSELicense for a published module
modules/Nested child modules
examples/Example calls of the module

Terraform does not require these file names; it reads every .tf file in the directory. The layout simply makes modules easier to read and lets the registry generate documentation. For composition, HashiCorp advises a flat module tree, where the root module connects small modules by passing one module's outputs into another's inputs.

Version constraints

The version argument takes a constraint string with these operators.

ConstraintAccepts
= 5.1.0 or 5.1.0Exactly 5.1.0
!= 5.1.0Any version except 5.1.0
>= 5.0.05.0.0 or newer
>= 5.0, < 6.0Any 5.x version
~> 5.15.1 or newer within 5.x
~> 5.1.05.1.0 or newer within 5.1.x

The ~> operator, the pessimistic constraint, allows only the rightmost version part to increase. HashiCorp advises pinning modules from outside your organization to avoid unexpected changes.

version works only with registries

The version argument applies only to modules from the public Terraform Registry or a private registry, such as the HCP Terraform private registry. For Git sources you pin with ?ref=, and local path modules have no version at all, because they are read in place.

Upgrading modules

terraform init installs the newest version that matches the constraint when no copy exists yet. Afterwards it keeps the installed version until you ask for an upgrade.

terraform init -upgrade

-upgrade checks for the newest versions of modules and providers that still match their constraints. The dependency lock file .terraform.lock.hcl records provider versions only; it does not lock module versions, so the constraint in the module block is your module pin.

Edit version constraintterraform initwith the upgrade flagNewest allowed versionterraform planreview changes

How the exam asks about this

  • "Which constraint lets a module take 2.3.x patches but not 2.4.0?" ~> 2.3.0.
  • "Can the version argument pin a module sourced from a Git repository?" No; use ref in the source URL.
  • "True or false: the dependency lock file pins module versions." False; it records provider versions only.

What to remember for the exam

  • A module block needs source; other arguments set the child's input variables.
  • Modules support count, for_each, depends_on and providers.
  • Read outputs as module.NAME.OUTPUT, or module.NAME["key"].OUTPUT for for_each instances.
  • version works only for public and private registry modules.
  • ~> 1.2 allows 1.2 and later 1.x versions; ~> 1.2.0 allows only 1.2.x.
  • terraform init -upgrade moves modules and providers to the newest versions their constraints allow.
Watch out

Changing a module's version constraint does nothing until you run terraform init again. If the installed version still matches the new constraint, you need terraform init -upgrade to pick up a newer release.

Common mistakes

Pinning a Git module with version. Terraform rejects a version argument on a non-registry source with an error. Put the tag in the source with ?ref=v1.2.0.

Trusting the lock file for modules. .terraform.lock.hcl only records providers. Without a version constraint, a fresh terraform init can pull a newer registry module than your teammate has.

Misreading the pessimistic operator. ~> 5.0 allows any 5.x version, not only 5.0.x. Write ~> 5.0.0 to stay on 5.0 patches.

Check yourself

  • Which module sources accept the version argument?

    Only modules from the public Terraform Registry or a private registry; Git sources use ref, and local paths have no versions.

  • What does ~> 3.1 allow?

    Version 3.1 and any later 3.x release, but not 4.0 or later.

  • Which command updates an installed module to the newest version its constraint allows?

    terraform init -upgrade, which also upgrades providers within their constraints.

Topic 2 of 2 in Terraform Modules

Test yourself on Terraform Modules

The full HashiCorp Terraform Associate 004 question bank has 600 questions, with timed practice exams and an explanation for every answer.

This study guide is independent and is not affiliated with, endorsed by, or sponsored by HashiCorp. Vendor names, certification names and exam codes are trademarks of their respective owners and are used for identification only.