Run Terraform the way teams do — saved plans applied exactly, multiple environments with workspaces, and an automated pipeline that plans on every PR and applies on merge.
Why: in automation you must apply EXACTLY what was reviewed, not re-plan and hope nothing changed. plan -out writes the plan to a file; apply of that file runs it with no prompt and no re-evaluation. This separation — plan, review, apply-the-saved-plan — is the backbone of safe CI/CD.
1) Produce a saved plan
terraform plan -out=tfplan2) Apply exactly that plan (no prompt, no re-plan)
terraform apply tfplanWhy: workspaces let one configuration keep separate state per environment — dev, staging, prod — without copying code. Each workspace has its own state file; terraform.workspace exposes the current name so you can vary values by environment. Note: for strong isolation many teams prefer separate directories/backends instead; workspaces suit lighter cases.
Create and switch to a workspace
terraform workspace new stagingList them (the * marks the current one)
terraform workspace listSwitch back
terraform workspace select defaultWhy: terraform.workspace is the current workspace name, so one configuration can size itself per environment — more replicas in prod, fewer in dev — without separate files. Combine it with a map lookup for clean per-environment values.
locals {
replicas = {
default = 1
staging = 2
prod = 5
}
count = local.replicas[terraform.workspace]
}
resource "local_file" "info" {
filename = "info.txt"
content = "env=${terraform.workspace} replicas=${local.count}"
}Why: the team workflow automates the plan/apply split: on a pull request, run fmt -check, validate, and plan so reviewers see the diff; on merge to main, run apply of the saved plan. Credentials come from the CI secret store via TF_VAR_ or provider env vars — never the repo. This GitHub Actions sketch shows the shape.
# .github/workflows/terraform.yml
on:
pull_request:
push:
branches: [main]
jobs:
terraform:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- run: terraform init
- run: terraform fmt -check
- run: terraform validate
- run: terraform plan -out=tfplan
# Apply only on the main branch, after review/merge
- if: github.ref == 'refs/heads/main'
run: terraform apply -auto-approve tfplan