Back to blog

February 10, 2026

Terraform Modules Are an Operating Model

The interesting part of a Terraform module strategy is not the modules themselves. It is the distribution of responsibility around them.

I started the Terraform Module Strategy repository as a reference implementation for how infrastructure code can be organized when the goal is not just getting a single environment to apply cleanly, but building something that scales across teams.

The repository is structured around three layers: foundation modules, pattern modules, and environments. That looks like a folder structure, but it is really an operating model.

Foundation modules keep primitives honest

Foundation modules define low-level building blocks: VPCs, security groups, KMS keys, S3 buckets, SNS topics, SQS queues, and IAM policies.

They should:

  • do one thing well
  • avoid environment-specific logic
  • expose clean, explicit inputs and outputs

That constraint matters because foundation modules are where reuse can quietly turn into coupling. If a primitive knows too much about a specific application or team, it stops being a foundation and becomes hidden policy.

Pattern modules encode the opinion

Pattern modules are where opinion belongs.

In this repo:

  • app-network composes VPC and security group foundations into an application networking baseline
  • event-driven composes SNS, SQS, IAM policy, DLQ handling, optional KMS encryption, FIFO support, and subscription wiring

This is the layer application teams should consume. It reduces decision fatigue without hiding important outputs. Instead of asking every team to reassemble the same infrastructure checklist, the platform provides a small set of coherent patterns with clear contracts.

Environments should stay boring

The envs/dev directory is intentionally thin. It consumes pattern modules and avoids defining infrastructure resources directly.

That is the point.

Environments should:

  • declare intent
  • pass configuration
  • remain repeatable

When environment directories become the place where exceptions and one-off resources accumulate, the module strategy starts to collapse.

A more scalable model is:

keep infrastructure logic in modules, and keep environments as validation and configuration layers.

Standards are part of the product

The repository treats quality controls as part of the system:

  • Terraform formatting and validation run in CI
  • terraform-docs ensures module documentation stays current
  • Modules use explicit version constraints, typed variables, and clear descriptions

This is not decoration.

For internal platform modules, documentation and validation are part of the developer experience. A module without a clear contract is not a platform product. It is just shared code.

The strategy

Terraform module design is less about collecting reusable snippets and more about deciding where different types of decisions should live.

  • Primitives live in foundation modules
  • Organizational defaults live in pattern modules
  • Environment intent lives in environment directories
  • CI and documentation enforce consistency

That separation is what makes the model scalable. It allows platform teams to improve standards and evolve patterns without forcing every application team to understand low-level AWS details.

This repository reflects how I think about Terraform in the context of internal platforms and developer experience systems.