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

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

  1. Account per env for prod isolation.
  2. Per-env tfvars + backend.
  3. Modules pinned to versions.
  4. 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

Newsletter

Get weekly AI workflows for DevOps engineers

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