Terraform module design patterns, resource composition conventions, and project structure standards. Use when designing module structure, choosing resource composition patterns, or setting up project layout for AWS Terraform modules.
This repository develops well-structured, reusable Terraform modules using raw resources that follow HashiCorp and organizational best practices.
variables.tf, outputs.tf, examples/, tests/terraform-aws-modules/)create_* boolean variables>= version constraints for providers in modules (maximize consumer compatibility)# examples/basic/main.tf
module "this" {
source = "../.."
name = "my-vpc"
vpc_cidr = "10.0.0.0/16"
environment = "dev"
tags = {
Application = "example"
ManagedBy = "terraform"
}
}
/
├── main.tf # Primary resource definitions
├── variables.tf # Input variables with validation
├── outputs.tf # Output values with descriptions
├── locals.tf # Computed values
├── versions.tf # Terraform and provider version constraints (required_version + required_providers)
├── README.md # Auto-generated via terraform-docs
├── CHANGELOG.md # Version history
├── examples/
│ ├── basic/ # Minimal usage example (with provider config)
│ └── complete/ # Full-featured example
├── modules/ # Submodules (optional)
├── tests/ # Terraform test files (.tftest.hcl)
└── .github/
└── workflows/ # CI/CD pipelines
this for single primary resource, descriptive names for multiplesfor_each over count for resource iteration (stable addresses)Security defaults per constitution sections 1.2 and 4.x. Key: zero trust, encryption by default, least privilege, sensitive = true on secrets.
For resource-level implementation patterns (VPC, IAM, compute, storage, database), see tf-implementation-patterns skill.
All taggable AWS resources MUST support tags via a tags variable. Use merge() to combine consumer tags with module defaults:
resource "aws_vpc" "this" {
# ...
tags = merge(var.tags, { Name = var.name })
}
Note: default_tags configuration belongs in examples/ provider blocks, not in the module root.
Use this for single primary resources. Use descriptive names for multiples:
resource "aws_vpc" "this" { ... }
resource "aws_subnet" "public" { ... }
resource "aws_subnet" "private" { ... }
>= version constraints for providers in modules