skills/terraform-module-builder/SKILL.md
Reusable Terraform module builder for AWS, GCP, and Azure infrastructure. Activate on: Terraform module, reusable IaC, provider configuration, state management, module registry, workspace management. NOT for: Kubernetes manifests (use kubernetes-manifest-generator), AWS CDK (use aws-cdk-builder), application deployment (use devops-automator).
npx skillsauth add curiositech/windags-skills terraform-module-builderInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Expert in building composable, tested, and version-controlled Terraform modules for multi-cloud infrastructure.
Module Size Decision Tree:
├─ Resource count > 50 OR complexity score > 8?
│ ├─ YES → Split into sub-modules with clear interfaces
│ └─ NO → Continue as single module
├─ Multiple provider types (AWS + GCP + K8s)?
│ ├─ YES → Separate modules per provider
│ └─ NO → Single provider module acceptable
└─ Team size > 15 OR multiple product teams?
├─ YES → Create module registry with versioning
└─ NO → Git submodules or local modules sufficient
| Team Size | Maturity | Backend Choice | Lock Mechanism | |-----------|----------|---------------|----------------| | 1-3 devs | Startup | Terraform Cloud Free | Built-in | | 4-10 devs | Growth | S3 + DynamoDB | DynamoDB table | | 10+ devs | Enterprise | S3 + DynamoDB OR Terraform Cloud Team | DynamoDB + state encryption | | Regulated | Any size | Self-hosted Consul OR Terraform Enterprise | Consul locks + audit logs |
Conditional Resource Decision:
IF environment_specific AND known_at_plan_time
→ Use count = var.enable_feature ? 1 : 0
IF data_driven AND multiple_instances
→ Use for_each with map of configurations
IF complex_branching OR resource_relationships
→ Use dynamic blocks with local values
Symptom: terraform plan takes >30 seconds, module has >50 resources, single file >1000 lines
Diagnosis: Module violates single responsibility principle
Fix: Extract logical boundaries (networking, compute, data) into separate modules with defined interfaces
Symptom: Error: provider "aws" was not configured by any provider blocks in child modules
Diagnosis: Child module declares provider block instead of inheriting from parent
Fix: Remove provider blocks from child modules, add only required_providers in versions.tf
Symptom: Resources recreate when boolean conditions change order: aws_instance.web[0] → aws_instance.web[1]
Diagnosis: Using count with conditional lists instead of for_each with stable keys
Fix: Replace count = length(var.subnets) with for_each = toset(var.subnets)
Symptom: "Backend configuration changed" errors, state file conflicts between team members
Diagnosis: Mixing local and remote state, or inconsistent backend configuration
Fix: Standardize on remote backend with locking, use terraform init -reconfigure
Symptom: Plan succeeds but apply fails with provider errors like "invalid CIDR" or "region not found"
Diagnosis: Missing input validation allows invalid values to reach provider
Fix: Add validation blocks: condition = can(cidrhost(var.cidr, 0))
Scenario: E-commerce module needs optional read replica based on environment and expected load.
Decision Process:
var.environment = "prod", var.expected_read_iops = 5000Implementation Choice:
# Option 1: count (avoid - creates aws_db_instance.replica[0])
resource "aws_db_instance" "replica" {
count = var.environment == "prod" && var.expected_read_iops > 3000 ? 1 : 0
# Problem: Index-based addressing, brittle to condition changes
}
# Option 2: for_each (preferred - creates aws_db_instance.replica["primary"])
resource "aws_db_instance" "replica" {
for_each = var.enable_read_replica ? { primary = var.replica_config } : {}
# Benefit: Stable resource addressing, easier to extend to multiple replicas
}
Novice Miss: Using boolean count without considering future extensibility
Expert Catch: Planning for multiple replicas (by region, by workload) using map-based for_each
Cost Impact: Production with replica = $400/month vs $200/month single instance
Do NOT use for:
kubernetes-manifest-generator for YAML/Helmaws-cdk-builder for TypeScript/Python CDK stacksdevops-automator for CI/CD workflowsterraform-iac-expert for ad-hoc TerraformWhen to delegate:
kubernetes-manifest-generatoraws-cdk-builderdevops-automatordata-ai
license: Apache-2.0 NOT for unrelated tasks outside this domain.
development
Use when designing caching strategies (cache-aside, write-through, write-behind), implementing distributed locks, building rate limiters, leaderboards, real-time streams (XADD/consumer groups), pub/sub, or tuning eviction policies. Triggers: thundering-herd on cache miss, dogpile on key expiry, Redlock vs SET-NX-PX choice, sliding-window rate limiter, hot-key on a single cluster slot, big-key blowup, MULTI/EXEC across slots, KEYS in production. NOT for Redis Cluster operations/admin (different domain), embedded KV (SQLite, leveldb), in-process LRU caches, or Memcached.
tools
Drawing the `'use client'` boundary correctly in React Server Components apps (Next.js App Router, RSC frameworks) — leaf-pushing, slot composition, serialization rules, and environment poisoning prevention. Grounded in react.dev and Next.js 16 docs.
development
Use when designing rate limiting for an API, choosing between token bucket / sliding window / leaky bucket / fixed window, implementing it in Redis, deciding edge (Cloudflare/Upstash) vs origin enforcement, sizing per-user vs per-IP vs per-endpoint quotas, returning the right 429 response with Retry-After, or fixing the boundary-burst bug in fixed-window limiters. Triggers: 429 too many requests, INCR + EXPIRE, ZADD + ZREMRANGEBYSCORE + ZCARD, X-RateLimit-Remaining header, Cloudflare WAF rate limiting rules, Upstash @upstash/ratelimit, leaky bucket shaping vs policing, distributed rate limiter consistency. NOT for DDoS mitigation specifically (different scale), CAPTCHA / bot management, full WAF design, or per-user quota billing.