Skip to content
CloudOps
All prompts
AI for Terraform Difficulty: Intermediate ClaudeChatGPT

Terraform Module Composition Prompt

Design Terraform modules — input/output contracts, composition, versioning, public vs private registry, when to abstract.

Target user
Engineers building reusable Terraform modules
Difficulty
Intermediate
Tools
Claude, ChatGPT

The prompt

You are a senior Terraform engineer who has built and maintained reusable modules used across many teams — strong inputs, clear outputs, versioned.

I will provide:
- The module purpose
- Current state
- Use case

Your job:

1. **Module design principles**:
   - Single responsibility (one logical concern)
   - Composable (works with other modules)
   - Parameterized (inputs over assumptions)
   - Stable outputs (downstream depends)
   - Documented
2. **For module structure**:
   ```
   mymodule/
   ├── main.tf
   ├── variables.tf
   ├── outputs.tf
   ├── versions.tf       # provider version requirements
   ├── README.md
   └── examples/
       └── basic/
           └── main.tf
   ```
3. **For variables.tf**:
   - Document each var (description)
   - Specify type
   - Default for optional
   - Validation
4. **For outputs.tf**:
   - Expose what consumers need
   - Stable interface
   - `sensitive = true` for secrets
5. **For versioning**:
   - Tag releases (semver)
   - Source with `?ref=v1.2.0`
   - Public registry: `registry.terraform.io/<ns>/<name>`
   - Private: git/HTTPS/OCI
6. **For composition**:
   - Root module wires children
   - Outputs of one → inputs of another
   - Loose coupling via data sources
7. **For abstraction level**:
   - Too thin: just a passthrough; adds nothing
   - Too thick: hides too much, hard to override
   - Sweet spot: encapsulates pattern + reasonable defaults
8. **For breaking changes**:
   - Major version bump
   - Migration guide
   - Avoid in module versions <1.0

Mark DESTRUCTIVE: changing required variables without migration, removing outputs that callers depend on, module versioning without backward compat plan.

---

Module purpose: [DESCRIBE]
Current state: [DESCRIBE]
Use case: [DESCRIBE]

Why this prompt works

Module design enables reuse. This prompt walks patterns.

How to use it

  1. Single responsibility.
  2. Clear inputs/outputs.
  3. Pin versions.
  4. Test before publishing.

Patterns

Module structure

modules/network/
├── main.tf
├── variables.tf
├── outputs.tf
├── versions.tf
├── README.md
└── examples/
    ├── simple/
    │   └── main.tf
    └── multi-az/
        └── main.tf

variables.tf

variable "vpc_cidr" {
  description = "CIDR block for the VPC"
  type        = string

  validation {
    condition     = can(cidrhost(var.vpc_cidr, 0))
    error_message = "vpc_cidr must be a valid CIDR block."
  }
}

variable "az_count" {
  description = "Number of availability zones to use"
  type        = number
  default     = 2

  validation {
    condition     = var.az_count >= 2 && var.az_count <= 6
    error_message = "az_count must be between 2 and 6."
  }
}

variable "tags" {
  description = "Tags applied to all resources"
  type        = map(string)
  default     = {}
}

variable "enable_flow_logs" {
  description = "Enable VPC flow logs"
  type        = bool
  default     = false
}

outputs.tf (stable contract)

output "vpc_id" {
  description = "ID of the VPC"
  value       = aws_vpc.main.id
}

output "public_subnet_ids" {
  description = "List of public subnet IDs"
  value       = aws_subnet.public[*].id
}

output "private_subnet_ids" {
  description = "List of private subnet IDs"
  value       = aws_subnet.private[*].id
}

output "availability_zones" {
  description = "List of availability zones used"
  value       = data.aws_availability_zones.available.names
}

versions.tf

terraform {
  required_version = ">= 1.5.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 5.0, < 6.0"
    }
  }
}

README.md template

# network module

VPC with public/private subnets across multiple AZs.

## Usage

\`\`\`hcl
module "network" {
  source  = "git::https://gitlab.example.com/platform/tf-modules.git//network?ref=v1.2.0"

  vpc_cidr = "10.0.0.0/16"
  az_count = 3
  tags     = { Environment = "production" }
}
\`\`\`

## Requirements

| Name | Version |
|---|---|
| terraform | >= 1.5.0 |
| aws | >= 5.0 |

## Inputs

| Name | Type | Default | Required |
|---|---|---|---|
| vpc_cidr | string | n/a | yes |
| az_count | number | 2 | no |
| tags | map(string) | {} | no |

## Outputs

| Name | Description |
|---|---|
| vpc_id | VPC ID |
| public_subnet_ids | Public subnet IDs |
| private_subnet_ids | Private subnet IDs |

See `examples/` for usage patterns.

Composition pattern

# Root module wires children
module "network" {
  source = "../modules/network"
  vpc_cidr = "10.0.0.0/16"
}

module "compute" {
  source = "../modules/compute"

  # outputs from network → inputs to compute
  vpc_id          = module.network.vpc_id
  subnet_ids      = module.network.private_subnet_ids
  instance_type   = "t3.medium"
}

module "monitoring" {
  source = "../modules/monitoring"

  # outputs from compute → inputs to monitoring
  instance_ids = module.compute.instance_ids
}

Module versioning (semver)

# Initial release
git tag v0.1.0 -m "Initial"
git push origin v0.1.0

# Patch (no breaking changes)
git tag v0.1.1 -m "Bug fix"
git push origin v0.1.1

# Minor (backward-compat features)
git tag v0.2.0 -m "Add IPv6 support"
git push origin v0.2.0

# Major (breaking change)
git tag v1.0.0 -m "Renamed variables, removed deprecated outputs"
git push origin v1.0.0

Common findings this catches

  • Module too thin (just wraps a resource) — collapse.
  • Module too fat (hides everything) — split or expose more.
  • No README → document.
  • No validation — add bounds checks.
  • Mutable version reference (?ref=main) → pin.
  • Tight coupling between modules → loosen via data sources.
  • Output removed in minor → use major bump.

When to escalate

  • Module catalog strategy — coordinate.
  • Public publishing — review.
  • Cross-org module ownership — agreements.

Related prompts

Newsletter

Get weekly AI workflows for DevOps engineers

Practical prompts, automation ideas, and tool reviews for infrastructure engineers. One email per week. No spam.