DEV Community

Mukami
Mukami

Posted on

A Workflow for Deploying Infrastructure Code with Terraform

Seven Steps. One Plan File. Zero Surprises.


Day 21 of the 30-Day Terraform Challenge — and today I learned that deploying infrastructure code safely requires discipline that application deployments don't need.

Yesterday I mapped the seven-step application workflow. Today I applied it to infrastructure — and discovered where the two workflows diverge and why those differences matter.


The Seven-Step Infrastructure Workflow

Step Action
1 Version control (Git)
2 Run locally (terraform plan -out)
3 Make code changes (feature branch)
4 Submit for review (PR with plan output)
5 Run automated tests (CI)
6 Merge and release (tag)
7 Deploy (apply saved plan file)

Step 1: Version Control

Every infrastructure change starts in Git. Not in the AWS Console.

git init
git add .
git commit -m "Day 21: Initial web server"
git push origin main
Enter fullscreen mode Exit fullscreen mode

Why this matters: Every change has an author, a timestamp, and a reason. No more mystery infrastructure.


Step 2: Run Locally — The Infrastructure Difference

For application code, running locally means executing the binary. For infrastructure, it means running terraform plan.

terraform plan -out=day21.tfplan
Enter fullscreen mode Exit fullscreen mode

The critical difference: You're not running the code. You're generating a diff against your state file. The plan shows exactly what will change in production.


Step 3: Make Code Changes

Create a feature branch and make your change. I added a CloudWatch alarm:

git checkout -b add-cloudwatch-alarm
# Edit main.tf to add the alarm resource
git add main.tf
git commit -m "Add CloudWatch CPU alarm"
git push origin add-cloudwatch-alarm
Enter fullscreen mode Exit fullscreen mode

Step 4: Submit for Review — The Infrastructure Difference

For application code, you review the code diff. For infrastructure, you review the plan output.

My PR description:

## What this changes
Adds a CloudWatch metric alarm for CPU utilization

## Terraform plan output
Plan: 1 to add, 0 to change, 0 to destroy.

## Resources affected
- Created: 1 (CloudWatch alarm)

## Blast radius
Low. Only adds monitoring. No impact on existing resources.

## Rollback plan
Remove the alarm resource and re-apply.
Enter fullscreen mode Exit fullscreen mode

Why this matters: The reviewer sees exactly what will change in production without running Terraform themselves.


Step 5: Run Automated Tests

GitHub Actions runs terraform validate, terraform fmt --check, and unit tests automatically on every PR.

Why this matters: Catch syntax and formatting errors before a human ever reviews the code.


Step 6: Merge and Release

After approval, merge and tag:

git checkout main
git pull origin main
git tag -a "v1.1.0" -m "Add CloudWatch CPU alarm"
git push origin v1.1.0
Enter fullscreen mode Exit fullscreen mode

Why this matters: Tags create rollback points. Every release is versioned.


Step 7: Deploy — The Infrastructure Difference

For application code, you deploy from CI. For infrastructure, you apply the saved plan file.

terraform apply day21.tfplan
Enter fullscreen mode Exit fullscreen mode

The critical difference: Using the saved plan guarantees that exactly what was reviewed is what gets applied. No surprises. No drift between plan and apply.


What I Deployed

A web server with a CloudWatch alarm:

Component Status
EC2 instance Running, serving HTTP
Security group Allow port 80
CloudWatch alarm Monitoring CPU > 80%

Verification:

$ curl -s http://56.228.18.125
<h1>Day 21: Infrastructure Deployment Workflow</h1>

$ aws cloudwatch describe-alarms --alarm-names day21-high-cpu
{
    "AlarmName": "day21-high-cpu",
    "StateValue": "OK",
    "Threshold": 80.0
}
Enter fullscreen mode Exit fullscreen mode

Infrastructure-Specific Safeguards

These have no equivalent in application code deployment:

1. Plan File Pinning

Always apply from a saved plan, never from a fresh plan.

# Correct — apply exactly what was reviewed
terraform plan -out=reviewed.tfplan
terraform apply reviewed.tfplan

# Risky — the plan may differ
terraform apply
Enter fullscreen mode Exit fullscreen mode

2. Blast Radius Documentation

Every PR must document what breaks if the apply fails.

3. State Backup

S3 bucket versioning must be enabled. Know how to restore a previous state.

4. Approval Gates for Destructive Changes

Any plan showing resource destruction requires explicit approval beyond PR review.


Infrastructure vs Application: Key Differences

Difference Why It Exists
Plan files, not binaries Infrastructure changes affect real resources; plan must be reviewed before apply
Blast radius A bad infrastructure deploy can destroy production data
State management Terraform tracks real resources; state corruption breaks everything

The Most Dangerous Step

The gap between terraform plan and terraform apply is where things go wrong. If infrastructure changes between plan and apply, the plan becomes invalid.

The safeguard: Save the plan file and apply it directly. Never run terraform apply without a plan file.

# Safe
terraform plan -out=day21.tfplan
terraform apply day21.tfplan

# Risky
terraform apply
Enter fullscreen mode Exit fullscreen mode

What I Learned

Plan output is the most important review artifact. Include it in every PR.

Blast radius matters. A bad infrastructure deploy can break more than a bad code deploy.

Plan file pinning is non-negotiable. Without it, you're applying something that might not match what was reviewed.

State is the source of truth. Protect it with versioning and backups.


The Bottom Line

Deploying infrastructure code requires the same seven steps as application code — plus infrastructure-specific safeguards.

Before After
Console clicks Pull requests with plan output
"Who changed this?" Git blame
Hope it works Plan file proves it
Can't roll back Tags and state versioning

Seven steps. Plan files. Blast radius documentation. State backups.

Infrastructure deployment shouldn't be risky. It should be reviewed, tested, and applied exactly as planned.


P.S. The moment I applied a saved plan file and saw exactly what was reviewed happen in production, I understood why teams adopt this workflow. It's not slower. It's safer. 🔧

Top comments (0)