Free — no signup required

Modules: The Lego Blocks

3 min read

Composition over Repetition

A module is the fundamental unit of reuse in Terraform. At its simplest, a module is just a directory containing .tf files. Every Terraform configuration you write is technically a module — the "root module." When you call another directory's code, that's a "child module."

Think of modules like functions in programming: they accept inputs (variables), perform work (create resources), and return outputs. The caller doesn't need to know the implementation details — just the interface.

A typical module directory holds its resource definitions, its input variables, its outputs, and a README, all in one self-contained folder. A root configuration calls it by pointing source at that directory, passes in whatever inputs the module declares (instance type, environment name, AMI ID), and can then reference anything the module exposes as an output — the module's public IP, say — the same way a function call passes arguments in and reads a return value out.

Input Validation

Modules are shared across teams. Without guardrails, someone will pass "production" when the module expects "prod", and the resulting resource will be named incorrectly or the wrong policy will be applied. Validation blocks catch this before any API call is made: a variable can declare a condition — membership in an allowed set of values, or a match against a naming pattern — plus an error message to show when that condition fails, so a bad input is rejected at plan time with a clear explanation instead of surfacing as a confusing resource-level error later.

Lifecycle Rules: Protecting Critical Resources

The lifecycle meta-argument gives you fine-grained control over how Terraform handles resource changes. This is critical for stateful resources like databases: a prevent_destroy flag makes Terraform refuse to apply any plan that would destroy the resource, and an ignore_changes list names specific attributes — an engine version bumped by an external maintenance window, a password rotated by a secrets manager — that Terraform should stop tracking entirely, so drift in those specific fields never triggers an unwanted replacement.

prevent_destroy = true is a safety net, not a guarantee. It only prevents destruction when the resource block still exists in the configuration. If you delete the entire resource block and run apply, Terraform will still destroy it — prevent_destroy only catches cases where a change to the existing block would cause a replacement.

Interview Tip

A common interview scenario: "Your team accidentally destroyed a production RDS instance with terraform apply. How would you prevent this in the future?" The answer covers three layers: prevent_destroy = true in the lifecycle block, enabling deletion protection at the AWS level (deletion_protection = true on the RDS resource), and requiring plan review in CI before any apply to production. Mentioning all three layers demonstrates operational maturity.

This is one of 18 chapters

Every chapter is free — Kubernetes, Terraform, SRE, distributed systems, and more — with fast daily review built in.

Sign up free