Subtopic•What are modules

Module Concept

In the early stages of infrastructure-as-code adoption, it is common to define all resources in a single fileset. As architecture scales, this "monolithic" approach becomes a bottleneck for speed, security, and collaborative engineering. Terraform Modules are the primary mechanism for breaking down complex infrastructure into small, reusable, and self-contained units. This chapter explores the theoretical concept of modules and how they enable professional scale.

1. Defining the Terraform Module

A module is fundamentally a container for multiple resources that are used together. Any folder containing a collection of .tf files is considered a module. Even if you don't explicitly create modules, you are always working within the "Root Module."

1.1 The Black Box Analogy

A professional module should be treated like a "Black Box."

  • Inputs: The module defines a set of variables that act as configuration parameters.
  • Logic: The module contains internal logic (resources, data sources, locals) that the consumer doesn't need to understand in detail.
  • Outputs: The module returns specific data points (IDs, ARNs, DNS names) that the calling configuration can use.

2. The Core Philosophy: DRY (Don't Repeat Yourself)

In a typical enterprise environment, you might need to deploy a "Standard Web Server" in ten different environments (Development, Testing, Production, etc.). Without modules, you would copy and paste the aws_instance, aws_security_group, and aws_ebs_volume blocks ten times.

The Module Advantage:

  • You write the "Web Server" logic once.
  • You call it multiple times, passing different parameters (e.g., instance_type = "t3.micro" for Dev vs. t3.large for Prod).
  • If you need to update the security policy for all web servers, you change it in the module code once, and Terraform propagates that change across all environments on the next apply.

3. Encapsulation and Abstraction

Modules provide a layer of abstraction between the "What" and the "How."

3.1 Hiding Complexity

A platform team might create a "Database" module that automatically includes:

  • An RDS instance.
  • A highly available Subnet Group.
  • A Security Group with specific ingress rules.
  • Mandatory tagging for Cost Center and Security Level.
  • Automatic snapshot policies.

The storage engineer or developer using the module doesn't need to know the specific syntax for aws_db_subnet_group; they simply call the database module and provide the db_name and allocated_storage.

3.2 Security and Governance

Modules are a critical tool for enforcing security standards. By forcing developers to use an approved "VPC Module," security teams can ensure that every VPC has logging enabled, no public subnets are created accidentally, and encryption is forced on all transit points.

4. Portability and the Service Catalog

A well-designed module is provider-agnostic in its configuration (though not in its resources). It should be easy to "drop in" to any project.

The "Service Catalog" Pattern: Large organizations often maintain a private "Service Catalog" of modules. A developer building a new application can pick a "Standard Kubernetes Module," a "Standard Postgres Module," and a "Standard VPC Module," and have a production-ready environment running in minutes instead of days.

5. The Standard Module Structure

Professional modules follow a rigid file structure to ensure they are readable and compatible with automated documentation tools like terraform-docs.

  • main.tf: The primary entry point where resources are defined.
  • variables.tf: Explicit definitions of all input parameters.
  • outputs.tf: Definitions of all data points the module shares with the caller.
  • versions.tf: Constraints on the Terraform version and required providers.
  • README.md: Human-readable documentation of what the module does.

6. Granularity: Finding the "Sweet Spot"

A common mistake in modular architecture is making modules either too small or too large.

  • Too Small: A module that only contains a single S3 bucket is often redundant and adds unnecessary complexity to the dependency graph.
  • Too Large: A module that creates an entire VPC, five Databases, and ten EC2 instances is a "Monolithic Module." It is hard to test, hard to change, and has a massive blast radius.

6.1 The "Functional Unit" Principle

The best practice is to group resources based on their Functional Lifecycle. If two resources are always created, updated, and destroyed together (like an EC2 instance and its dedicated Security Group), they belong in the same module.

7. The Lifecycle of a Module Call

When you call a module in your code:

  1. Initialize: terraform init downloads the module source (from local disk, Git, or Registry) and places it in the .terraform/modules directory.
  2. State: Terraform tracks the resources inside the module with a prefix, e.g., module.web_server.aws_instance.this.
  3. Change Management: If you update the module version in your code, terraform init -upgrade is required to fetch the new logic.

8. Summary

Modules are the building blocks of manageable infrastructure. They transform Terraform from a simple scripting language into a true engineering framework. By embracing modularity, you move from "Copy-Paste Engineering" to "Architectural Composition," allowing your infrastructure to scale while maintaining high standards of security, reliability, and developer productivity.

←Previous ModuleCore Resources and Data Sources