Deployment Rollback Testing: How to Verify Your Rollback Works Before You Need It

Deployment Rollback Testing: How to Verify Your Rollback Works Before You Need It

Rollback is the escape hatch you reach for when a deployment goes wrong. Most teams assume it works. Few test it. The teams that discover their rollback is broken do so at the worst possible moment — during a production incident, under pressure, with customers waiting.

This guide covers how to test rollback procedures systematically so that when you actually need to roll back, it takes minutes and works reliably.

Why Rollback Fails in Practice

Rollback sounds simple: redeploy the previous version. In reality, several things break this assumption:

Database migrations with no down migration: If the new version ran ALTER TABLE ADD COLUMN, the old version may fail to start because it doesn't know about that column, or it may fail queries because it expects columns that don't exist in its ORM mapping.

Incompatible state in external systems: If the new version wrote data in a new format to Redis, S3, or a message queue, the old version may fail to parse that data.

Dependency version changes: If the deployment updated a shared library, a dependent service, or a third-party integration, rolling back the application binary doesn't roll back those dependencies.

Stale container images: If the rollback target image tag (v1.2.3) was deleted from the container registry, Kubernetes can't pull it.

Testing rollback surfaces these problems before an incident.

The Rollback Testing Matrix

For each deployment, evaluate rollback risk across three dimensions:

Risk Factor Low Risk High Risk
Schema changes None Add/drop columns, rename tables
Data format changes None New serialization format
API contract changes Backward compatible Breaking changes
External service updates None New webhook endpoints, API version bump
Configuration changes None New required env vars

High-risk deployments require a tested rollback path before going to production.

Testing Kubernetes Rollbacks

Kubernetes maintains rollout history, making rollback straightforward:

# Deploy new version
kubectl set image deployment/my-app app=my-app:v2.0.0 -n production

# Verify the new version is running
kubectl rollout status deployment/my-app -n production

# Simulate a failure — trigger rollback
kubectl rollout undo deployment/my-app -n production

# Verify rollback completed
kubectl rollout status deployment/my-app -n production

# Check which version is now running
kubectl get deployment my-app -n production -o jsonpath='{.spec.template.spec.containers[0].image}'

To test rollback in a staging environment before a production deployment:

# 1. Deploy v2.0.0 to staging
kubectl set image deployment/my-app app=my-app:v2.0.0 -n staging
kubectl rollout status deployment/my-app -n staging

# 2. Run smoke tests to confirm v2.0.0 works
robot smoke/ --variable ENV_URL:https://staging.example.com

# 3. Trigger rollback to v1.9.0
kubectl rollout undo deployment/my-app -n staging
kubectl rollout status deployment/my-app -n staging

# 4. Run smoke tests again to confirm v1.9.0 works
robot smoke/ --variable ENV_URL:https://staging.example.com

# 5. If step 4 passes, rollback procedure is verified

If step 4 fails, you have a rollback problem to solve before the production deployment.

Testing Database Migration Rollbacks

Down migrations are the most common rollback failure point. Every up migration needs a corresponding down migration that is tested.

Using Flyway:

-- V2__add_user_preferences.sql (up migration)
ALTER TABLE users ADD COLUMN preferences JSONB DEFAULT '{}';
CREATE INDEX idx_users_preferences ON users USING gin(preferences);

-- U2__add_user_preferences.sql (undo migration — requires Flyway Teams)
DROP INDEX idx_users_preferences;
ALTER TABLE users DROP COLUMN preferences;

Test the round-trip:

# Apply up migration
flyway migrate

# Verify application works with new schema
robot tests/smoke/

# Apply down migration
flyway undo

# Verify application works with old schema
robot tests/smoke/

If the smoke suite passes both times, the schema change is safe to roll back.

For teams not using Flyway Teams (undo migrations require a license), the alternative is additive-only migrations — never dropping or renaming columns in the same deployment that removes application code using them. Remove unused columns in a follow-up deployment after the rollback window has passed.

Automated Rollback Triggers

Manual rollback is slow. Automate it when specific conditions are met after deployment:

# GitHub Actions: auto-rollback on smoke test failure
- name: Run smoke tests
  id: smoke
  run: robot smoke/ --variable ENV_URL:${{ vars.PRODUCTION_URL }}
  continue-on-error: true

- name: Rollback on failure
  if: steps.smoke.outcome == 'failure'
  run: |
    echo "Smoke tests failed — rolling back"
    kubectl rollout undo deployment/my-app -n production
    kubectl rollout status deployment/my-app -n production
    
    # Notify
    curl -X POST ${{ secrets.SLACK_WEBHOOK }} \
      -d '{"text": "Production deployment rolled back — smoke tests failed after deploy"}'
    
    exit 1

This gives you automatic rollback within minutes of a bad deployment, before most users experience the failure.

Rollback Verification Tests

After a rollback, you need tests that confirm the system is back to a known-good state. These differ from smoke tests in one way: they specifically verify that any state written by the bad version doesn't cause problems for the old version.

*** Test Cases ***
Old Version Handles New Data Gracefully
    # Verify that data written by v2.0.0 (if any) doesn't break v1.9.0
    Go To    ${BASE_URL}/api/users?format=v2
    ${response}=    Get Response
    # v1.9.0 should either handle v2 format or fall back gracefully
    Should Not Contain    ${response.body}    500 Internal Server Error
    Should Not Contain    ${response.body}    KeyError
    Should Not Contain    ${response.body}    null pointer

Configuration Rollback Is Complete
    # Verify that new env vars added in v2.0.0 don't cause v1.9.0 to fail
    ${response}=    HTTP    GET    ${BASE_URL}/health
    Should Be Equal As Integers    ${response.status}    200
    ${body}=    Evaluate    json.loads('''${response.body}''')
    Should Be Equal    ${body['status']}    healthy

Rollback Runbook

Document the rollback procedure so any engineer can execute it under pressure:

# Rollback Runbook — my-app

## Trigger Conditions
Roll back if any of these occur within 30 minutes of deployment:
- Smoke test suite fails
- Error rate > 2x pre-deployment baseline
- P50 latency > 500ms (vs. baseline 150ms)
- Any 5xx rate > 1%

## Step 1: Initiate Rollback (2 minutes)
kubectl rollout undo deployment/my-app -n production
kubectl rollout status deployment/my-app -n production

## Step 2: Verify Rollback (3 minutes)
Run the smoke suite:
robot smoke/ --variable ENV_URL:https://app.example.com

## Step 3: Confirm Metrics Recovery (5 minutes)
Check Grafana dashboard: grafana.example.com/d/deployments
Error rate should return to baseline within 5 minutes.

## Step 4: Notify
Post in #incidents:
"[ROLLBACK COMPLETE] Rolled back my-app to v{PREVIOUS_VERSION}.
Smoke tests: PASS. Metrics: recovering.
Next step: RCA in progress."

Test the runbook quarterly by executing it in staging.

Rollback Windows and Policies

Define how long your rollback window is. After a certain point, rolling back becomes more dangerous than moving forward:

  • First 30 minutes: Low-risk rollback. Little user data has been written in the new format.
  • 30 minutes to 2 hours: Medium risk. Some data may need migration before rollback.
  • After 2 hours: High risk. Rollback may require a forward fix instead.

Build this policy into your deployment tooling so that rollback is offered automatically during the window and requires explicit confirmation after.

Summary

Rollback testing is not glamorous, but it's the kind of work that prevents a 2 AM incident from turning into a 4-hour outage. Test your rollback path before every significant deployment, automate rollback triggers based on objective signals, and keep a runbook that any engineer can follow without thinking. The goal is to make rollback a boring, reliable procedure — not a scramble.

Read more

Start now free