Terraform Multi-Environment Design Prompt
Design Terraform for multiple environments — dev/staging/prod separation, tfvars patterns, account boundaries, promotion workflow.
- Target user
- Platform engineers structuring Terraform across environments
- Difficulty
- Intermediate
- Tools
- Claude, ChatGPT
The prompt
You are a senior platform engineer who has structured Terraform deployments across many environments — separate accounts, tfvars per env, promotion workflows. I will provide: - Environment count and account model - Current Terraform structure - Promotion needs Your job: 1. **Account boundary**: - **Single account, multi-env**: cheap; less isolation - **Account per env** (recommended for prod): true blast radius limit - **Account per team + env**: max isolation; complex 2. **For directory layout**: - `envs/<env>/` per env (see workspaces-vs-dirs) - Or `accounts/<account>/<env>/` 3. **For tfvars**: - Per-env `terraform.tfvars` - Or `-var-file=prod.tfvars` at CLI - Sensitive vars via env var or secrets manager 4. **For shared modules**: - In repo: `modules/` shared across envs - In separate repo: pin to version - Public registry: pin version 5. **For promotion**: - dev → staging → prod - Same module versions - Tested config first - Manual approval for prod 6. **For variable schema differences**: - Some envs need different vars - Common base + per-env additions - Validate at plan time 7. **For provider configuration**: - Per-env account assume role - Per-env region 8. **For drift between envs**: - Periodic plan to catch - Investigate divergence Mark DESTRUCTIVE: tfvars committing secrets, wrong env's tfvars passed (cross-env damage), shared state across envs. --- Env model: [DESCRIBE] Current structure: [DESCRIBE] Promotion needs: [DESCRIBE]
Why this prompt works
Multi-env design is foundational. This prompt walks patterns.
How to use it
- Account per env for prod isolation.
- Per-env tfvars + backend.
- Modules pinned to versions.
- Promotion workflow with approval.
Patterns
Directory + tfvars
infrastructure/
├── modules/
│ ├── network/
│ ├── compute/
│ └── monitoring/
├── envs/
│ ├── dev/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ ├── outputs.tf
│ │ ├── backend.tf
│ │ └── terraform.tfvars
│ ├── staging/
│ └── prod/
└── shared/
└── providers.tf
Per-env main.tf
# envs/prod/main.tf
module "network" {
source = "git::https://gitlab.example.com/platform/tf-modules.git//network?ref=v1.4.0"
cidr_block = var.network_cidr
az_count = var.az_count
enable_flow_logs = var.enable_flow_logs
}
module "compute" {
source = "git::https://gitlab.example.com/platform/tf-modules.git//compute?ref=v2.1.0"
vpc_id = module.network.vpc_id
instance_type = var.instance_type
instance_count = var.instance_count
ssh_key_name = var.ssh_key_name
}
Per-env terraform.tfvars
# envs/prod/terraform.tfvars
network_cidr = "10.10.0.0/16"
az_count = 3
enable_flow_logs = true
instance_type = "m5.xlarge"
instance_count = 6
ssh_key_name = "prod-shared"
# envs/dev/terraform.tfvars
network_cidr = "10.0.0.0/16"
az_count = 2
enable_flow_logs = false
instance_type = "t3.medium"
instance_count = 2
ssh_key_name = "dev-shared"
Provider with assume role per env
# envs/prod/providers.tf
provider "aws" {
region = "us-east-1"
assume_role {
role_arn = "arn:aws:iam::PROD_ACCOUNT_ID:role/TerraformProd"
session_name = "TerraformProdApply"
}
default_tags {
tags = {
Environment = "production"
ManagedBy = "Terraform"
}
}
}
CI promotion workflow
# .gitlab-ci.yml
stages: [plan-dev, apply-dev, plan-staging, apply-staging, plan-prod, apply-prod]
.tf-job: &tf-job
image: hashicorp/terraform:1.9
before_script:
- terraform -chdir=envs/$ENV init
plan-dev:
<<: *tf-job
stage: plan-dev
variables: { ENV: dev }
script:
- terraform -chdir=envs/dev plan -out=tfplan
artifacts: { paths: [envs/dev/tfplan], expire_in: 1 week }
apply-dev:
<<: *tf-job
stage: apply-dev
variables: { ENV: dev }
needs: [plan-dev]
script:
- terraform -chdir=envs/dev apply tfplan
rules:
- if: $CI_COMMIT_BRANCH == "main"
plan-prod:
<<: *tf-job
stage: plan-prod
variables: { ENV: prod }
script:
- terraform -chdir=envs/prod plan -out=tfplan
artifacts: { paths: [envs/prod/tfplan], expire_in: 1 week }
rules:
- if: $CI_COMMIT_TAG =~ /^v\d+/
apply-prod:
<<: *tf-job
stage: apply-prod
variables: { ENV: prod }
needs: [plan-prod]
script:
- terraform -chdir=envs/prod apply tfplan
environment:
name: production
deployment_tier: production
rules:
- if: $CI_COMMIT_TAG =~ /^v\d+/
when: manual # manual approval for prod
Common findings this catches
- Same tfvars deployed to multi-env → wrong values.
- Missing per-env backend → state collision.
- Secrets in tfvars → external secrets manager.
- Provider not env-scoped → cross-account.
- Module version unpinned → drift between envs.
- No prod approval gate → safety risk.
- Drift across envs → periodic plan + alert.
When to escalate
- Account vending strategy — finance / IT.
- Cross-team module library — coordinate.
- Compliance per env — security.
Related prompts
-
Terraform CI/CD: Atlantis, Cloud, GitOps Prompt
Choose and configure Terraform CI/CD — Atlantis, Terraform Cloud, Spacelift, custom CI; plan/apply workflows, approvals.
-
Terraform State Backend Design Prompt
Design Terraform state backend — S3+DynamoDB, GCS, Azure Blob, encryption, locking, versioning, cross-account access.
-
Terraform Workspaces vs Directory Structure Prompt
Choose between Terraform workspaces and directory-per-env — when each is appropriate, migration patterns.