Branching & Deployment Strategy

How Opsitron handles terraform plan, apply, and branch management for infrastructure changes.

Opsitron uses a branch-per-request strategy with plan and apply on the branch — changes are verified in your actual AWS environment before merging to main. This is different from the common “merge first, apply after” pattern and provides stronger safety guarantees.

The Pattern

main (always reflects deployed state)
  │
  ├── request/14 ← AI creates branch + PR
  │     ├── tofu plan (on PR open)
  │     ├── tofu apply (after approval)
  │     └── merge to main (after successful apply)
  │
  ├── request/15
  │     ├── tofu plan
  │     ├── tofu apply
  │     └── merge to main
  │
  └── (main always matches what's deployed)

Why Plan and Apply on the Branch

Most GitOps tools follow a merge-then-apply pattern: merge the PR to main, then apply from main. This has a problem — if the apply fails, main contains code that doesn’t match your infrastructure. You’re left with drift between your repo and your actual state.

Opsitron’s apply-then-merge pattern avoids this:

  1. Plan on the branch — when the PR is opened, the infrastructure workflow runs tofu plan against the branch code and posts the results as a PR comment
  2. Apply on the branch — after staff reviews and approves, Opsitron triggers tofu apply from the branch. The actual infrastructure is updated.
  3. Merge after success — only after the apply succeeds does the PR merge to main. Main always reflects the real deployed state.

If the apply fails, the PR stays open. You can fix the code on the branch and try again. Main is never polluted with broken configuration.

Request Lifecycle

Each infrastructure request maps to a branch:

Request StateBranch StateWhat Happens
SubmittedRequest queued for AI planning
PlanningAI analyzing infrastructure
Plan Reviewrequest/{number} createdAI created branch with terraform code
In ProgressPR openedInfrastructure workflow runs plan
Plan ApprovedApply triggeredtofu apply runs on the branch
Apply SucceededPR mergedBranch merged to main, branch deleted
CompletedBranch cleaned upMain reflects the deployed state

Environment Promotion

For application infrastructure that deploys to multiple environments (dev → staging → prod), each environment has its own directory and state:

apps/web-app/
  ├── dev1/      ← applied first
  ├── stage1/    ← applied after dev1 succeeds
  └── prod1/     ← applied after stage1 + client approval

A single PR can contain changes to multiple environments. The infrastructure workflow detects which directories changed and runs plan/apply for each independently. Promotion follows the configured pipeline:

  1. Dev — auto-approved, applies immediately
  2. Staging — requires staff approval before apply
  3. Production — requires staff + client approval, may have a deployment window

Each environment’s apply is independent — a failure in staging doesn’t affect dev, and prod won’t apply until staging succeeds.

Drift Detection

The infrastructure workflow includes drift detection during apply. Before applying, it re-runs tofu plan to verify the expected changes match what was planned on PR open. If unexpected changes appear (drift from manual changes or concurrent modifications), the apply is blocked with a warning.

This catches situations where:

  • Someone made a manual change in the AWS console
  • Another request modified the same resources concurrently
  • AWS made automatic changes (e.g., security group rule updates)

Cost Estimation

Every plan includes a cost estimate via OpenInfraQuote, an open-source tool that calculates monthly cost impact from terraform plan output. The estimate is posted as a PR comment alongside the plan output, giving reviewers immediate visibility into cost implications before approving.

What Main Represents

The main branch is the source of truth for deployed infrastructure. At any point:

  • main matches what’s actually deployed in AWS
  • Feature branches (request/*) represent pending changes
  • There is no “desired state” that differs from actual state
  • git log main is a complete history of every infrastructure change

This means you can always tofu plan from main and expect zero changes (no drift). If you see drift, it means something changed outside of Opsitron — which the platform detects and flags.

Config Repository vs. Application Repository

This branching strategy applies to config repositories (infrastructure code) and LZA config repositories (Landing Zone Accelerator configuration). Application repositories (your app code) use standard Git flow — push to main triggers builds, and deployments are managed separately through the container/static deploy workflows.

Repository TypeBranch StrategyDeploy Trigger
Config (infra)Branch per request, apply then mergePR plan/apply workflow
LZA ConfigBranch per request, apply then mergeLZA CodePipeline
ApplicationStandard Git flow (push to main)Build workflow → auto-deploy