What is a Terraform module, and why should you modularize configuration?

4 minbeginnerterraformmodulesfundamentals

Quick Answer

A module is simply a directory of `.tf` files — every Terraform configuration is a module, and any module can be called by another via a `module` block. You modularize to encapsulate a reusable piece of infrastructure (e.g., "a standard VPC" or "an ECS service") behind a small set of input variables and outputs, so consumers don't need to know its internals. This reduces duplication across environments/teams, enforces organizational standards (tagging, security groups) in one place, and makes changes safer since they're tested once and reused everywhere.

Detailed Answer

A key insight for interviews: every Terraform configuration is a module — even a plain directory of .tf files with no module blocks anywhere is technically "the root module." What people usually mean by "a module" is a reusable unit designed to be called from elsewhere.

Calling a module

module "vpc" {
  source = "./modules/vpc"

  cidr_block  = "10.0.0.0/16"
  environment = "prod"
}

Inside modules/vpc/, you'd have .tf files declaring variable blocks (cidr_block, environment) as its inputs, resources it creates internally, and output blocks exposing values like the created VPC's ID back to the caller.

Why modularize

  1. Encapsulation. A module hides implementation details behind a small, deliberate interface (its variables and outputs) — consumers don't need to know it internally creates a VPC, three subnets, a route table, and an internet gateway; they just pass cidr_block and get back vpc_id.
  2. Reuse across environments/teams. The same modules/vpc can be called from dev, staging, and prod root configurations with different variable values, guaranteeing structural consistency instead of three hand-written, slowly-diverging copies of near-identical VPC code.
  3. Enforcing standards centrally. If your org requires every resource to have specific tags, or every S3 bucket to have encryption enabled, baking that into a shared module means every consumer gets it automatically — fixing an issue in one place fixes it everywhere the module is used (after consumers bump their version pin).
  4. Safer, smaller blast radius for changes. A well-tested, versioned module can be changed and validated once, rather than every team member independently copy-pasting and modifying raw resource blocks with slightly different mistakes.

The tradeoff

Modules add a layer of indirection — over-modularizing trivial, single-use configuration can make it harder to see what's actually being created without digging into module internals. The rule of thumb: modularize genuinely repeated patterns (a standard VPC, a standard microservice deployment), not every single resource.

Related Resources