
Terraform Patterns
Structure Terraform modules with proven flat-and-composable layouts before solo builders scale cloud infra past a single root module.
Overview
terraform-patterns is an agent skill most often used in Operate (also Build, Ship) that teaches numbered Terraform module design patterns with copy-ready HCL for solo-maintained cloud stacks.
Install
npx skills add https://github.com/alirezarezvani/claude-skills --skill terraform-patternsWhat is this skill?
- Documents a flat-module directory layout (main, variables, outputs, versions, locals, backend, tfvars) for small stacks
- Shows AWS VPC and subnet examples with locals-based naming, merge tags, count-based subnets, and variable validation blo
- Encodes Terraform 1.5+ and provider pinning patterns in versions.tf for reproducible solo deployments
- Teaches naming and tagging conventions via locals.common_tags and environment-scoped name_prefix
- Reference-style HCL snippets agents can paste into new modules without ad-hoc chat guesses
- Flat module reference uses a seven-file single-directory layout (main, variables, outputs, versions, locals, backend, tf
- Example pins Terraform >= 1.5.0 and AWS provider ~> 5.0 in required_providers
Adoption & trust: 527 installs on skills.sh; 17.5k GitHub stars; 2/3 security scanners passed (skills.sh audits).
What problem does it solve?
You are growing past a single main.tf blob and need a consistent module layout and tagging conventions your agent can generate without breaking Terraform 1.x provider pinning or state layout.
Who is it for?
Solo builders on AWS (or similar) who want agent-assisted Terraform with a clear seven-file flat layout before splitting into nested modules.
Skip if: Teams that already enforce a mature internal module registry, pure ClickOps workflows, or stacks with no Terraform in the pipeline.
When should I use this skill?
You or your agent are designing or refactoring Terraform modules and need established directory and HCL patterns instead of one-off layouts.
What do I get? / Deliverables
After applying these patterns you get a documented flat-module skeleton with versions, backend, locals, validated variables, and tagged resources ready to plan and iterate in your repo.
- Flat-module directory blueprint with standard .tf file roles
- Copy-ready HCL for versions, locals, tagged VPC/subnet resources, and validated variables
Recommended Skills
Journey fit
Spans multiple journey phases - primary shelf plus alternate fits below.
Terraform module shape is a production concern first surfaced when operating and evolving cloud stacks, even though teams often write modules earlier during build. Infra subphase is the canonical shelf for IaC module design references that govern how state, variables, and backends are organized in live environments.
Where it fits
Bootstrap a first AWS VPC and public subnets with validated environment variables before wiring the application stack.
Align versions.tf, backend.tf, and tfvars layout so staging and production plans stay reproducible on launch week.
Refactor a sprawl of resources in one directory into the documented flat-module files before extracting shared child modules.
Apply consistent locals-based tags and name_prefix rules when adding subnets or resizing CIDR blocks in an existing module.
How it compares
Use as a procedural module-style guide instead of asking the agent to invent Terraform file layout from generic cloud tutorials.
Common Questions / FAQ
Who is terraform-patterns for?
Indie and solo developers using Claude Code, Cursor, or Codex who write or maintain their own Terraform and want repeatable module structure without a platform team.
When should I use terraform-patterns?
Use it during Build when scaffolding backend infra, during Ship when hardening launch-ready environments, and during Operate when refactoring root modules or standardizing tags and variables before the next apply.
Is terraform-patterns safe to install?
It is reference documentation and HCL examples only; review the Security Audits panel on this Prism page and treat generated infra plans like any other Terraform change before apply.
SKILL.md
READMESKILL.md - Terraform Patterns
# Terraform Module Design Patterns Reference ## Pattern 1: Flat Module (Single Directory) Best for: Small projects, < 20 resources, single team ownership. ``` project/ ├── main.tf ├── variables.tf ├── outputs.tf ├── versions.tf ├── locals.tf ├── backend.tf └── terraform.tfvars ``` ### Example: Simple VPC + EC2 ```hcl # versions.tf terraform { required_version = ">= 1.5.0" required_providers { aws = { source = "hashicorp/aws" version = "~> 5.0" } } } # locals.tf locals { name_prefix = "${var.project}-${var.environment}" common_tags = { Project = var.project Environment = var.environment ManagedBy = "terraform" } } # main.tf resource "aws_vpc" "main" { cidr_block = var.vpc_cidr enable_dns_hostnames = true enable_dns_support = true tags = merge(local.common_tags, { Name = "${local.name_prefix}-vpc" }) } resource "aws_subnet" "public" { count = length(var.public_subnet_cidrs) vpc_id = aws_vpc.main.id cidr_block = var.public_subnet_cidrs[count.index] availability_zone = var.availability_zones[count.index] tags = merge(local.common_tags, { Name = "${local.name_prefix}-public-${count.index + 1}" Tier = "public" }) } # variables.tf variable "project" { description = "Project name used for resource naming" type = string } variable "environment" { description = "Deployment environment" type = string validation { condition = contains(["dev", "staging", "prod"], var.environment) error_message = "Environment must be dev, staging, or prod." } } variable "vpc_cidr" { description = "CIDR block for the VPC" type = string default = "10.0.0.0/16" validation { condition = can(cidrhost(var.vpc_cidr, 0)) error_message = "Must be a valid CIDR block." } } variable "public_subnet_cidrs" { description = "CIDR blocks for public subnets" type = list(string) default = ["10.0.1.0/24", "10.0.2.0/24"] } variable "availability_zones" { description = "AZs for subnet placement" type = list(string) default = ["us-east-1a", "us-east-1b"] } # outputs.tf output "vpc_id" { description = "ID of the created VPC" value = aws_vpc.main.id } output "public_subnet_ids" { description = "IDs of public subnets" value = aws_subnet.public[*].id } ``` --- ## Pattern 2: Nested Modules (Composition) Best for: Multiple environments, shared patterns, team collaboration. ``` infrastructure/ ├── environments/ │ ├── dev/ │ │ ├── main.tf │ │ ├── backend.tf │ │ └── terraform.tfvars │ ├── staging/ │ │ └── ... │ └── prod/ │ └── ... └── modules/ ├── networking/ │ ├── main.tf │ ├── variables.tf │ └── outputs.tf ├── compute/ │ └── ... └── database/ └── ... ``` ### Root Module (environments/dev/main.tf) ```hcl module "networking" { source = "../../modules/networking" project = var.project environment = "dev" vpc_cidr = "10.0.0.0/16" public_subnet_cidrs = ["10.0.1.0/24", "10.0.2.0/24"] private_subnet_cidrs = ["10.0.10.0/24", "10.0.11.0/24"] } module "compute" { source = "../../modules/compute" project = var.project environment = "dev" vpc_id = module.networking.vpc_id subnet_ids = module.networking.private_subnet_ids instance_type = "t3.micro" instance_count = 1 } module "database" { source = "../../modules/database" project = var.project environment = "dev" vpc_id = module.networking.vpc_id subnet_ids = module.networking.private_subnet_ids instance_class = "db.t3.micro" allocated_storage = 20 db_password = var.db_password } ``` ### Key Rules - Child modules never call other child modules - Pass values explicitly — no hidden data source lookups in children - Provider configuration only in root module