Terraform in CI/CD
Automate plan and apply in a pipeline so infrastructure changes go through review like any code.
Running Terraform in a CI/CD pipeline turns infrastructure changes into reviewable, auditable pull requests.
A typical pipeline
- On a pull request: run
fmt -check,validate, andplan, then post the plan for reviewers. - On merge to main: run
apply -auto-approveto roll out the change.
Requirements
- Remote state with locking so parallel runs are safe.
- Credentials injected securely (OIDC roles beat long-lived keys).
-input=falseso commands never block waiting for a prompt.
Example
# Steps a CI job typically runs (non-interactive)
terraform init -input=false
terraform fmt -check -recursive
terraform validate
terraform plan -input=false -out=tfplan
# On the main branch only, after review:
terraform apply -input=false -auto-approve tfplanWhen to use it
- A GitHub Actions workflow posts the terraform plan output as a pull-request comment so reviewers can see what will change before approving the merge.
- A GitLab CI pipeline runs terraform apply on the main branch only after a plan succeeds and a manual approval gate is passed in the pipeline UI.
- An Atlantis server runs plan on every PR and apply on merge, ensuring every infrastructure change is reviewed and applied automatically from Git events.
More examples
GitHub Actions plan on PR
A GitHub Actions workflow that initializes Terraform and runs plan on every pull request targeting main.
name: Terraform Plan
on:
pull_request:
branches: [main]
jobs:
plan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
with:
terraform_version: "1.9.0"
- run: terraform init
- run: terraform plan -no-color
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}Apply only on main merge
Triggers terraform apply automatically when code is merged to main, completing the plan-on-PR / apply-on-merge pattern.
name: Terraform Apply
on:
push:
branches: [main]
jobs:
apply:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- run: terraform init
- run: terraform apply -auto-approve
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}Save and apply plan file in CI
Demonstrates saving the plan to a file in the plan stage and applying that exact file in the apply stage for deterministic CI deployments.
# In the plan job:
terraform plan -out=tfplan
# Upload tfplan as a CI artifact, then in the apply job:
# Download the artifact, then:
terraform apply tfplan
# Applies exactly the diff that was reviewed β no surprises
Discussion