Skip to main content
Terraform modules use a parent–child relationship to organize reusable infrastructure. The root module (also called the parent or calling module) invokes one or more child modules. Child modules encapsulate the resources and configuration that actually create infrastructure — for example, a TLS certificate module, a load balancer module, a Kubernetes cluster module, or a database module. The parent module’s role is to call those child modules and provide the inputs they need.
A purple slide titled "Module Block: Parent Module vs. Child Module" explaining that a parent (calling) module references and configures other modules while a child module is the reusable infrastructure component being called. A diagram on the right shows a Parent Module pointing to two Child Modules.
Modules can be sourced from the Terraform Registry, local directories, Git repositories, or other supported locations. This flexibility enables teams to share well-designed infrastructure components and keep root configurations clean and maintainable.
When you reference a remote module (for example, from the Terraform Registry), running terraform init in your working directory downloads the module into the local .terraform directory so Terraform can use it.

Where modules come from

Parent (root/calling) module: module block

A module block in the root module tells Terraform to invoke a child module. The block has:
  • A local name (for example, module "vpc").
  • A source that points to the child module location.
  • Additional arguments corresponding to the child module’s input variables.
Example parent module calling a VPC module from the Registry:
Notes:
  • The module block name (vpc) is a local identifier; choose a name that fits your codebase (for example prod_vpc, dev_vpc).
  • Keys inside the block (such as name, cidr, azs) must match the variable names expected by the child module.
  • Values can be literals, parent variables (var.*), outputs from data resources, or expressions.

Child module: variables, resources, and outputs

A child module is a regular Terraform configuration composed of:
  • variable blocks to declare inputs,
  • resource blocks to create infrastructure,
  • output blocks to export values.
Design child modules to be configurable via variables so they can be reused across environments. Example of a simple child module that accepts name and cidr and creates an AWS VPC resource:
Key points:
  • Resource blocks live in the child module; the parent normally does not contain resource blocks that the child creates.
  • Variables are the module’s configuration surface and make the module reusable.
  • Outputs expose values (for example, the VPC ID) so the parent or other modules can reference them.

Passing values and retrieving outputs

When the root (parent) module calls a child module, it passes input variables. The child uses those inputs to create resources, then exposes outputs that the parent can reference. Example flow showing a parent declaring a variable, calling a child module, and exporting the child’s output: Root module (calling the child module):
Child module (local modules/vpc or remote source) — simplified:
How this works:
  1. The root module sets cidr_block and calls module "prod_vpc", passing cidr = var.cidr_block and name = "my-vpc".
  2. Terraform initializes and, if the module source is remote, downloads the module during terraform init.
  3. The child module receives inputs, creates resources (for example, an AWS VPC), and exposes outputs such as vpc_id.
  4. The parent references child outputs using module.<MODULE_NAME>.<OUTPUT_NAME>, e.g. module.prod_vpc.vpc_id.
You can chain modules: for example, a subnet module can accept vpc_id as input where that value originates from module.prod_vpc.vpc_id. Chaining enables clear separation of responsibilities and reusability.
Ensure the input attribute names you provide in the parent module match the variable names declared in the child module. For example, if the child declares variable "cidr", then the parent must pass cidr = ..., not vpc_cidr = ..., unless the child expects vpc_cidr.

Quick comparison: Parent vs Child

Best practices

  • Keep child modules focused on a single responsibility (for example: VPC, database, or IAM).
  • Make modules configurable via variables; avoid hard-coded values.
  • Export only necessary outputs to minimize coupling between modules.
  • Version remote modules and pin versions to avoid unexpected changes.
  • Document input variables and outputs inside module README files.
Modules let you express reusable infrastructure patterns while keeping root configurations concise — use them to standardize and scale your infrastructure-as-code.

Watch Video