interview-prep

Crisp answer: A module is a reusable, self-contained package of Terraform configuration with defined inputs (variables) and outputs. The root module is your working directory. Child modules are called with a module block.

Why use modules:

  • Reuse infrastructure patterns across environments (dev/staging/prod)
  • Encapsulate complexity behind a clean interface
  • Enforce organisational standards (e.g. every VPC must have flow logs)
  • Reduce duplication across teams

Module structure:

modules/
└── vpc/
    ├── main.tf        # Resources
    ├── variables.tf   # Input variables
    ├── outputs.tf     # Exported values
    └── README.md      # What this module does and how to use it

Calling a module:

module "networking" {
  source = "./modules/vpc"        # Local path
  # or:
  source  = "terraform-aws-modules/vpc/aws"  # Terraform Registry
  version = "~> 5.0"             # Version constraint

  # Pass input variables:
  cidr_block = "10.42.0.0/16"
  azs        = ["eu-west-2a", "eu-west-2b"]
  project    = var.project
}

# Use module outputs:
resource "aws_instance" "web" {
  subnet_id = module.networking.private_subnet_ids[0]
}

Module versioning:

# Terraform Registry modules support version constraints:
source  = "terraform-aws-modules/eks/aws"
version = "~> 20.0"   # any 20.x

# For local modules, use git refs:
source = "git::https://github.com/myorg/terraform-modules.git//vpc?ref=v1.2.0"

Flat vs nested modules:

Keep module nesting shallow (max 2 levels deep). Deep nesting makes terraform output and terraform state references verbose and hard to debug.

Standard project structure:

project/
├── main.tf           # module calls and resource glue
├── variables.tf      # root input variables
├── outputs.tf        # root outputs
├── versions.tf       # required_providers and required_version
├── backend.tf        # remote state config
├── terraform.tfvars  # variable values (never commit secrets here)
└── modules/
    ├── networking/
    ├── database/
    ├── compute/
    └── security/

What to say in the interview:

"Modules are the Terraform equivalent of functions. They take input variables, create resources, and expose outputs. I use modules to enforce consistency: every VPC follows the same structure, every database gets the same backup and encryption config, and teams can't forget to add flow logs because the module adds them. For root modules I keep a flat structure: main.tf for module calls, variables.tf, outputs.tf, backend.tf. Modules go in a modules/ directory and are versioned separately. The Terraform Registry has good community modules for EKS and VPC, but I always read them before using them."


My notes