home / skills / williamzujkowski / cognitive-toolworks / terraform-module-patterns
This skill helps you design reusable Terraform modules with validation, outputs, composition, and Terratest testing for reliable infrastructure.
npx playbooks add skill williamzujkowski/cognitive-toolworks --skill terraform-module-patternsReview the files below or copy the command above to add this skill to your agents.
---
name: "Terraform Module Best Practices"
slug: "terraform-module-patterns"
description: "Design reusable Terraform modules with variable validation, output schemas, module composition, and testing (Terratest)."
capabilities:
- "module structure design with validated variables"
- "output schema definition and documentation"
- "module composition and registry publishing"
- "Terratest test generation and CI/CD integration"
inputs:
- name: "module_type"
type: "string"
required: true
enum: ["network", "compute", "database", "composite"]
- name: "cloud_provider"
type: "string"
required: true
enum: ["aws", "azure", "gcp", "multi-cloud"]
- name: "testing_required"
type: "boolean"
required: false
default: true
outputs:
- name: "module_structure"
type: "object"
description: "Directory layout with recommended files"
- name: "variables_tf"
type: "string"
description: "Input variables with validation rules"
- name: "outputs_tf"
type: "string"
description: "Output values with descriptions"
- name: "test_code"
type: "string"
description: "Terratest Go tests"
- name: "examples"
type: "string"
description: "Usage examples and documentation"
keywords: ["terraform", "modules", "iac", "validation", "terratest", "composition"]
version: "1.0.0"
owner: "cognitive-toolworks"
license: "Apache-2.0"
security:
pii: "none"
secrets: "never hardcode; use variable injection + secrets manager"
audit: "include module versioning and change documentation"
links:
docs:
- "https://developer.hashicorp.com/terraform/language/modules/develop"
- "https://developer.hashicorp.com/terraform/registry/modules/publish"
- "https://terratest.gruntwork.io/docs/"
---
## Purpose & When-To-Use
Use when designing reusable Terraform modules that require:
- Input validation and type constraints
- Clear output contracts for module consumers
- Composition patterns for complex infrastructure
- Automated testing with Terratest
- Registry publishing and versioning
**Trigger conditions:**
- "Create a Terraform module for [infrastructure component]"
- "Add validation to Terraform variables"
- "Write Terratest tests for [module]"
- "Publish module to Terraform Registry"
## Pre-Checks
- **Authoritative time**: Set `NOW_ET` to ISO 8601 in `America/New_York` using NIST/time.gov semantics: `2025-10-26T02:31:29-0400`
- **Module type validation**: Ensure `module_type` is one of: network, compute, database, composite
- **Cloud provider support**: Verify provider-specific features and resource availability
- **Terraform version**: Check compatibility with `>= 1.0` for validation features
- **Source freshness**: Validate against current Terraform language spec and provider docs
## Procedure
### Tier 1 — Basic Module Structure (T1≤2000 tokens)
1. **Define module layout:**
```
terraform-<name>/
main.tf # Primary resources
variables.tf # Input variables with validation
outputs.tf # Output values with descriptions
versions.tf # Provider version constraints
README.md # Usage documentation
examples/ # Usage examples
basic/
tests/ # Terratest tests
```
2. **Create `variables.tf` with validation:**
- Use `type` constraints (string, number, bool, list, map, object, set, tuple, any)
- Add `validation` blocks for business logic constraints
- Include `description` and `default` where appropriate
- Use `sensitive = true` for secrets
3. **Define `outputs.tf` with clear contracts:**
- Document output purpose and format
- Use `description` for all outputs
- Mark sensitive outputs with `sensitive = true`
- Group related outputs logically
4. **Establish versioning in `versions.tf`:**
- Pin Terraform version: `required_version = ">= 1.5"`
- Pin provider versions with `~>` for minor updates
- Document version rationale in comments
### Tier 2 — Module Composition & Publishing (T2≤6000 tokens)
1. **Implement composition patterns:**
- **Child modules**: Extract repeated resources into sub-modules
- **Dependency injection**: Pass outputs from one module as inputs to another
- **Data-only modules**: Use `data` sources for discovery/lookups
- **For-each patterns**: Use `for_each` with maps for dynamic resources
2. **Add comprehensive examples:**
- **Basic example**: Minimal required inputs
- **Complete example**: All features enabled
- **Composition example**: Integration with other modules
- Each example should be self-contained and runnable
3. **Prepare for Registry publishing:**
- Follow naming convention: `terraform-<PROVIDER>-<NAME>`
- Create Git tags matching semantic versioning: `v1.0.0`
- Write comprehensive `README.md` with inputs/outputs tables
- Add `LICENSE` file (Apache-2.0, MIT, etc.)
- Include module registry metadata in repository
4. **Document module contracts:**
- Input variable requirements and defaults
- Output value structures and types
- Provider configuration requirements
- Resource naming conventions
### Tier 3 — Testing & CI/CD Integration (T3≤12000 tokens)
1. **Create Terratest tests:**
- Install Terratest: `go get github.com/gruntwork-io/terratest/modules/terraform`
- Write test structure:
- Setup: Configure test inputs
- Deploy: `terraform.InitAndApply(t, terraformOptions)`
- Validate: Assert expected outputs and resource state
- Teardown: `defer terraform.Destroy(t, terraformOptions)`
- Test different scenarios: minimal, complete, error cases
2. **Implement validation tests:**
- Test variable validation rules trigger correctly
- Verify output schemas match documentation
- Check resource dependencies and ordering
- Validate provider authentication patterns
3. **Set up CI/CD pipeline:**
- **Lint stage**: `terraform fmt -check`, `terraform validate`
- **Security stage**: `tfsec`, `checkov`, `terrascan`
- **Test stage**: Run Terratest suite in isolated environment
- **Docs stage**: Auto-generate docs with `terraform-docs`
- **Release stage**: Tag and publish to registry
4. **Add pre-commit hooks:**
- Format code: `terraform fmt -recursive`
- Validate syntax: `terraform validate`
- Update docs: `terraform-docs markdown table --output-file README.md`
- Security scan: `tfsec .`
## Decision Rules
- If `module_type == "composite"` → require Tier 2 composition patterns
- If `testing_required == true` → require Tier 3 Terratest implementation
- If publishing to registry → require semantic versioning and comprehensive README
- If variable validation fails in tests → emit specific validation error message
- If module has >5 required variables → recommend using `object` type for grouping
- If module creates >10 resources → recommend breaking into child modules
- **Abort conditions:**
- Missing provider configuration
- Circular module dependencies
- Hardcoded secrets or credentials
- Missing required variable descriptions
## Output Contract
**module_structure:**
```json
{
"root": ["main.tf", "variables.tf", "outputs.tf", "versions.tf", "README.md"],
"examples": ["basic", "complete"],
"tests": ["<module_name>_test.go"],
"docs": ["README.md", "CHANGELOG.md"]
}
```
**variables_tf:** String containing Terraform variable definitions with:
- `type` constraint
- `description` field
- `validation` blocks where applicable
- `default` values for optional inputs
- `sensitive` flag for secrets
**outputs_tf:** String containing output definitions with:
- `description` for each output
- `sensitive` flag where needed
- Logical grouping (e.g., network_ids, instance_details)
**test_code:** Go test file using Terratest framework with:
- Setup and teardown logic
- Terraform init/apply/destroy
- Output validation assertions
- Resource state checks
**examples:** Directory structure with runnable examples:
- `examples/basic/main.tf` — minimal configuration
- `examples/complete/main.tf` — all features enabled
- Each with `README.md` explaining usage
## Examples
**Example (≤30 lines): AWS VPC Module with Validation**
```hcl
# variables.tf
variable "vpc_cidr" {
type = string
description = "CIDR block for VPC"
validation {
condition = can(cidrhost(var.vpc_cidr, 0))
error_message = "Must be valid IPv4 CIDR block."
}
}
variable "subnet_count" {
type = number
description = "Number of subnets to create"
validation {
condition = var.subnet_count >= 2 && var.subnet_count <= 16
error_message = "Subnet count must be between 2 and 16."
}
}
# outputs.tf
output "vpc_id" {
description = "ID of the created VPC"
value = aws_vpc.main.id
}
output "subnet_ids" {
description = "List of subnet IDs"
value = aws_subnet.main[*].id
}
```
## Quality Gates
- **Token budgets**: T1≤2k (basic module structure), T2≤6k (composition + docs), T3≤12k (testing + CI/CD)
- **Example size**: ≤30 lines in `SKILL.md`; full examples in `examples/` directory
- **Variable validation**: All required variables must have `description`; validation rules for business logic
- **Output documentation**: All outputs must have `description` field
- **Testing coverage**: Minimum 3 test scenarios (basic, complete, error handling)
- **Security**: No hardcoded secrets; use `sensitive` flag; scan with `tfsec`
- **Versioning**: Semantic versioning for releases; provider version constraints in `versions.tf`
- **Formatting**: All code must pass `terraform fmt`
- **Documentation**: Auto-generated docs match actual inputs/outputs
## Resources
- **Terraform Module Development** (accessed 2025-10-26): https://developer.hashicorp.com/terraform/language/modules/develop
- **Terraform Module Publishing** (accessed 2025-10-26): https://developer.hashicorp.com/terraform/registry/modules/publish
- **Terraform Variable Validation** (accessed 2025-10-26): https://developer.hashicorp.com/terraform/language/values/variables#custom-validation-rules
- **Terratest Documentation** (accessed 2025-10-26): https://terratest.gruntwork.io/docs/
- **Terratest Terraform Module** (accessed 2025-10-26): https://terratest.gruntwork.io/docs/getting-started/quick-start/#example-2-terraform
- **HashiCorp Module Standards** (accessed 2025-10-26): https://developer.hashicorp.com/terraform/language/modules/develop/structure
- **Terraform Testing Best Practices** (accessed 2025-10-26): https://developer.hashicorp.com/terraform/language/modules/testing-experiment
This skill guides design and delivery of reusable Terraform modules with strong variable validation, explicit output schemas, clear composition patterns, and automated testing using Terratest. It focuses on practical structure, registry-ready publishing, and CI/CD integration to ensure reliable, maintainable modules.
It inspects module requirements and enforces pre-checks such as Terraform version, module_type and provider capabilities, then generates a canonical module layout (main.tf, variables.tf, outputs.tf, versions.tf, examples, tests). It produces validated variable declarations, documented outputs, example usage, Terratest Go tests, and CI pipeline recommendations for linting, security scanning, testing, and release.
What Terraform version is required?
Use Terraform >= 1.0; recommended required_version = ">= 1.5" to use recent validation features.
How many tests are required?
Aim for at least three Terratest scenarios: minimal, complete, and error/validation cases to cover happy and failure paths.
When should I split into child modules?
If the module creates more than ~10 resources or has complex divergent responsibilities, break into child modules for reuse and maintainability.