Implement GitOps workflows with ArgoCD and Flux for automated, declarative Kubernetes...
npx skills add williamzujkowski/cognitive-toolworks --skill "Terraform Module Best Practices"
Install specific skill from multi-skill repository
# Description
Usage examples and documentation
# SKILL.md
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_ETto ISO 8601 inAmerica/New_Yorkusing NIST/time.gov semantics:2025-10-26T02:31:29-0400 - Module type validation: Ensure
module_typeis one of: network, compute, database, composite - Cloud provider support: Verify provider-specific features and resource availability
- Terraform version: Check compatibility with
>= 1.0for validation features - Source freshness: Validate against current Terraform language spec and provider docs
Procedure
Tier 1 — Basic Module Structure (T1≤2000 tokens)
-
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 -
Create
variables.tfwith validation: - Use
typeconstraints (string, number, bool, list, map, object, set, tuple, any) - Add
validationblocks for business logic constraints - Include
descriptionanddefaultwhere appropriate -
Use
sensitive = truefor secrets -
Define
outputs.tfwith clear contracts: - Document output purpose and format
- Use
descriptionfor all outputs - Mark sensitive outputs with
sensitive = true -
Group related outputs logically
-
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)
- 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
datasources for discovery/lookups -
For-each patterns: Use
for_eachwith maps for dynamic resources -
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
-
Prepare for Registry publishing:
- Follow naming convention:
terraform-<PROVIDER>-<NAME> - Create Git tags matching semantic versioning:
v1.0.0 - Write comprehensive
README.mdwith inputs/outputs tables - Add
LICENSEfile (Apache-2.0, MIT, etc.) -
Include module registry metadata in repository
-
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)
- 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
-
Implement validation tests:
- Test variable validation rules trigger correctly
- Verify output schemas match documentation
- Check resource dependencies and ordering
-
Validate provider authentication patterns
-
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
-
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
objecttype 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:
{
"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
# 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 inexamples/directory - Variable validation: All required variables must have
description; validation rules for business logic - Output documentation: All outputs must have
descriptionfield - Testing coverage: Minimum 3 test scenarios (basic, complete, error handling)
- Security: No hardcoded secrets; use
sensitiveflag; scan withtfsec - 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
# Supported AI Coding Agents
This skill is compatible with the SKILL.md standard and works with all major AI coding agents:
Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.