Terraform plan on PRs, apply on merge
Terraform plan on PRs, apply on merge
The most common Terraform pipeline runs `terraform fmt -check` and `terraform validate` always, `terraform plan` on every pull request, and a manually-gated `terraform apply` on the main branch.
Conversion notes
- •On GitHub, the apply job uses an `environment:` with required reviewers as the manual gate.
- •On GitLab, `when: manual` on the apply job is the gate; combine with `rules:` to ensure it only appears for main-branch pushes.
- •On CircleCI, the apply job is a `type: approval` workflow node followed by the actual apply.
- •On Bitbucket, the apply runs in `pipelines.custom.deploy` (manual trigger).
Side-by-side implementation
name: terraform
on:
pull_request:
push:
branches: [main]
jobs:
plan:
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
- uses: actions/upload-artifact@v4
with:
name: tfplan
path: tfplan
apply:
needs: [plan]
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
environment: production
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- uses: actions/download-artifact@v4
with:
name: tfplan
- run: terraform init
- run: terraform apply tfplan
stages: [plan, apply]
plan:
stage: plan
image: hashicorp/terraform:1.7
script:
- terraform init
- terraform fmt -check
- terraform plan -out=tfplan
artifacts:
paths: [tfplan]
apply:
stage: apply
image: hashicorp/terraform:1.7
needs: [plan]
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
when: manual
script:
- terraform init
- terraform apply tfplan
version: 2.1
jobs:
plan:
docker:
- image: hashicorp/terraform:1.7
steps:
- checkout
- run: terraform init
- run: terraform fmt -check
- run: terraform plan -out=tfplan
- persist_to_workspace:
root: .
paths: [tfplan]
apply:
docker:
- image: hashicorp/terraform:1.7
steps:
- checkout
- attach_workspace:
at: .
- run: terraform apply tfplan
workflows:
main:
jobs:
- plan
- hold:
type: approval
requires: [plan]
filters:
branches: { only: [main] }
- apply:
requires: [hold]
filters:
branches: { only: [main] }
image: hashicorp/terraform:1.7
pipelines:
default:
- step:
name: plan
script:
- terraform init
- terraform fmt -check
- terraform plan -out=tfplan
artifacts: [tfplan]
custom:
deploy:
- step:
name: plan
script:
- terraform init
- terraform plan -out=tfplan
artifacts: [tfplan]
- step:
name: apply
trigger: manual
script:
- terraform init
- terraform apply tfplan
Related Tools
YAML Formatter
Format and validate YAML. Convert YAML to JSON or JSON to YAML. Supports 2 and 4 space indentation.
Cron Builder
Visual builder for cron-job schedules.
Gitignore Generator
Generate .gitignore files for any language, framework, or IDE — 100+ templates, 100% client-side.
JSON Schema Generator
Generate a JSON Schema from one or more sample JSONs — drafts 2020-12, 2019-09, 7, 6, 4. Detects formats (date-time, email, uuid, ipv4, uri), extracts $defs, validates with AJV, and exports to YAML, TypeScript, and Zod. 100% in your browser.
AI Coding Rules
Curated rules-file library and generator for Cursor, Claude Code, GitHub Copilot, Windsurf, Cline, Aider, Continue, and Cody. Browse 20 hand-crafted .cursorrules / CLAUDE.md / copilot-instructions.md files for popular stacks, build a custom one with the wizard, or convert any rules file between AI-tool formats.