# terraform / modules / architecture

Building Blocks of Infrastructure: Reusable Modules

A Terraform module is a container for multiple resources that are used together. Instead of copy-pasting 200 lines of VPC, subnet, route table, and gateway definitions across every application repository, you package it as a reusable module with defined inputs and outputs.

module "vpc" { ... }REUSABLE
source"./modules/aws-vpc"
cidr_block"10.0.0.0/16"
outputs.vpc_id"vpc-0a982fbc12"
1
Module Codebase
10+
Deployments
0
Duplication
# concept

Root Modules vs Child Modules

Every Terraform project has at least one module, known as the Root Module (the working directory where you run terraform apply). When the root module references another directory or repository using a module block, that called block is a Child Module.

TypeDefinitionExecution
Root ModuleTop-level directory with backend.tf and CLI execution contextRuns terraform init & apply
Child ModuleReusable directory or Git repository instantiated by a root moduleCalled via module "name" { source = ... }
Published ModuleCommunity or private verified module published to Terraform RegistryPinned with exact version tags
encapsulation

Encapsulation & Abstraction

Application developers don't need to know every nuance of AWS VPC Internet Gateways and NAT routing. They pass cidr = "10.0.0.0/16" to the VPC module, and the module provisions standard company-approved network architecture.

# file layout

Standard Module Directory Layout

directory treeSTANDARD FILES
1 2 3 4 5 6 7 8 9
modules/aws-vpc/
├── main.tf          # Resources: VPC, subnets, route tables
├── variables.tf     # Input parameters required by module
├── outputs.tf       # Values exported to caller
├── versions.tf      # Required Terraform & provider versions
└── README.md        # Usage examples and documentation

Golden Rules for Module Authors

  • No Hardcoded Backend: Never declare a backend block inside a child module.
  • No Hardcoded Provider Configuration: Child modules should inherit providers configured in the root module.
  • Explicit Inputs: Document all variables with clear descriptions and type constraints.
# usage

Calling a Module in the Root Project

main.tfCALLING CHILD MODULE
1 2 3 4 5 6 7 8 9 10 11 12 13
module "vpc" {
  source = "./modules/aws-vpc"

  # Pass required input arguments
  vpc_cidr            = "10.0.0.0/16"
  public_subnet_cidrs = ["10.0.1.0/24", "10.0.2.0/24"]
  environment         = "production"
}

# Access exported outputs from the module
resource "aws_instance" "web" {
  ami           = "ami-0123456789abcdef0"
  instance_type = "t3.micro"
  subnet_id     = module.vpc.public_subnet_ids[0]
}
initialization

Run terraform init After Adding Modules

Whenever you add, modify, or change the source of a module block, you must run terraform init so Terraform can download or index the module into the local .terraform/modules/ cache.

# sources

Where Modules Live: Sources & Versioning

Source TypeSource Syntax ExampleUse Case
Local Directory source = "./modules/vpc" Monorepo or project-specific sub-components
Git Repository source = "git::https://github.com/myorg/tf-vpc.git?ref=v1.4.0" Private organization shared libraries with Git tag pinning
Terraform Registry source = "terraform-aws-modules/vpc/aws"
version = "~> 5.0"
Battle-tested community modules for AWS, Azure, GCP
main.tfPUBLIC REGISTRY MODULE
1 2 3 4 5 6 7 8 9
module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~> 5.0"

  name = "prod-vpc"
  cidr = "10.0.0.0/16"

  azs             = ["ap-south-1a", "ap-south-1b"]
  private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24"]
}
version pinning

Always Pin Module Versions

Never omit the version or ?ref= tag when sourcing external modules. Without version pinning, upstream breaking changes could instantly break your production CI/CD builds.

# architecture

Module Composition in Real Systems

Network Module (VPC)
Outputs: vpc_id, subnets
Security Module (SG)
Takes vpc_id, outputs sg_id
App Module (EC2 / ALB)
Takes subnet_ids & sg_id
# guidelines

Enterprise Best Practices

RuleWhy It Matters
Single ResponsibilityKeep modules focused (e.g. modules/s3 or modules/vpc, not one gigantic monomodule).
Expose Essential OutputsOutput ARNs and IDs so downstream resources can integrate smoothly.
Use Semantic VersioningTag Git repositories with v1.0.0, v1.1.0 for safe updates.
Document with terraform-docsAuto-generate markdown tables for inputs and outputs in README.md.