Skip to content
Back to Deployment

Blue-Green Deployment Strategy

Two-environment switch with instant rollback, traffic shifting, and database migration safety.

CI/CDIntermediate

Why

Blue-green keeps two identical production environments and shifts 100% of traffic atomically. New version (green) is staged and smoke-tested while blue serves live traffic; the switch is instant and rollback is just flipping back.

Zero downtime, no partial-rollout inconsistency.

When

Use blue-green for stateless web apps where you need instant rollback and can afford 2x infrastructure. Avoid for apps with long-running WebSockets (connections break on switch) or without a load balancer that supports target swapping.

How

1. Provision two envs — blue (current live) and green (idle), identical infra + config 2. Deploy to green — CI/CD targets green, runs migrations (forward-only, backward-compatible) 3. Smoke test green — hit green URL directly (bypass LB), run health checks + key user flows 4. Pre-warm green — ramp up instances, run cache priming so first user request isn't cold 5. Switch traffic — LB swaps target group from blue to green (ALB target-group swap, 1 API call) 6. Monitor — watch error rate + latency for 5-10 min; if spike, swap back to blue (instant rollback) 7. Decommission blue — keep for rollback window (e.g. 1h), then scale to 0 or repurpose as next green 8. Database — expand/contract pattern: green adds new column (expand), blue still writes old; after switch, migrate writes (contract)

Example

# deploy.sh — blue-green with AWS ALB target groups #!/bin/bash set -euo pipefail BLUE_TG="arn:aws:elasticloadbalancing:...:targetgroup/blue/abc" GREEN_TG="arn:aws:elasticloadbalancing:...:targetgroup/green/xyz" LISTENER_ARN="arn:aws:elasticloadbalancing:...:listener/app/myapp/80/def" # 1. Deploy new image to green (ECS service auto-scaling) aws ecs update-service --service myapp-green --force-new-deployment aws ecs wait services-stable --services myapp-green # 2. Smoke test green directly (via its internal DNS) GREEN_URL="http://myapp-green.internal:3000/health" for i in {1..10}; do curl -sf "$GREEN_URL" && break || sleep 5 done # 3. Swap listener default action to green target group aws elbv2 modify-listener --listener-arn "$LISTENER_ARN" \ --default-actions Type=forward,TargetGroupArn="$GREEN_TG" echo "Traffic switched to green. Monitoring for 10 min..." START=$(date +%s) while [ $(( $(date +%s) - START )) -lt 600 ]; do ERRORS=$(aws cloudwatch get-metric-statistics \ --namespace AWS/ApplicationELB --metric-name HTTPCode_ELB_5XX \ --dimensions Name=LoadBalancer,Value=app/myapp/80 \ --start-time $(date -u -d '5 min ago' +%FT%TZ) \ --end-time $(date -u +%FT%TZ) --period 60 --statistics Sum | jq '.Datapoints[0].Sum') [ "${ERRORS:-0}" -gt 10 ] && { echo "Error spike! Rolling back"; aws elbv2 modify-listener --listener-arn "$LISTENER_ARN" --default-actions Type=forward,TargetGroupArn="$BLUE_TG"; exit 1; } sleep 30 done echo "Blue-green deploy successful"

Common Problems

  • ⚠Database migration breaks blue — green runs a destructive migration while blue still serves traffic
  • ⚠Sticky sessions break on switch — users logged into blue get 401 on green (different session store)
  • ⚠No monitoring window — switch happens, team walks away, error spike detected 30 min later in prod
  • ⚠2x infra cost always on — green stays provisioned 24/7 even between deploys, wasting budget

Best Practices

  • ✓Use expand/contract DB migrations — green adds (expand), switch, then remove old (contract) in next deploy
  • ✓Share session store (Redis) between blue and green — sticky sessions survive the switch
  • ✓Automate the 10-min monitoring window — script rolls back on error-rate threshold, no human needed
  • ✓Scale green to 0 between deploys — spin up only during deploy, saves 50% infra cost

FAQ

How is blue-green different from a rolling update?

Blue-green switches all traffic at once to the new (green) environment, keeping the old (blue) idle for instant rollback. Rolling updates replace instances gradually — slower but need only spare capacity, not a full duplicate environment.

How do I handle database migrations in blue-green?

Migrations must be backward-compatible — both blue and green run against the same DB during the switch. Apply additive migrations (new columns) before deploying, destructive ones (drop columns) only after blue is decommissioned.

What if the green environment fails health checks?

Traffic stays on blue — the switch never happens. Monitor green's health endpoint before routing traffic. Set an auto-rollback: if green error rate exceeds 1% in the first 5 min, route back to blue automatically.

How do I manage two environments cost-effectively?

Keep blue at full capacity (serves traffic) and green at minimum scale (1 instance) until health checks pass, then scale green up and blue down. This halves the cost vs. running both at full capacity permanently.

When is blue-green a bad choice?

When your app uses WebSockets or long-lived connections — the instant switch drops all active sessions. Use rolling updates or a canary strategy instead. Blue-green is best for stateless HTTP request/response apps.