Back to Blog
Guide8 min read2026-05-01

Zero Downtime Migration: How to Move Your App Without Downtime

A complete guide to migrating a live production application to a new cloud platform without taking it offline or losing a single request.

Zero Downtime Migration: How to Move Your App Without Downtime

A maintenance window is a negotiation: you're asking your users to accept service interruption in exchange for a better future. Most of the time, that negotiation is unnecessary. With the right strategy, you can migrate a live production application — code, database, and all — to a new cloud platform without dropping a single request. This guide covers the complete playbook for zero-downtime application migration.

Why Traditional Migrations Cause Downtime

Traditional migrations cause downtime for one of three reasons:

  1. 1DNS propagation delay — you point DNS to the new server and wait for the old one to drain
  2. 2Database unavailability — the database is taken offline to ensure a consistent export
  3. 3Application deployment gap — the old app is stopped before the new one is confirmed healthy

Zero-downtime migration eliminates all three through parallel operation, traffic shifting, and health-check-driven cutover.

The Core Pattern: Blue-Green Migration

Blue-green migration means running old (blue) and new (green) environments simultaneously and shifting traffic between them. The key insight: never stop blue until green is fully verified.

Internet → Load Balancer / DNS
              │
     ┌────────┴────────┐
     ▼                 ▼
  [BLUE]            [GREEN]
  Old Env           New Env
  (100%)            (0% → 100%)

Step 1: Deploy the New Environment Without Routing Traffic to It

Set up your new environment on PandaStack — containers, databases, environment variables — but don't update DNS yet.

npm install -g @pandastack/cli
panda login
panda init

# Deploy to PandaStack (gets a unique pandastack.io URL)
git push origin main

# Verify the new deployment is healthy — use the internal URL, not your domain
curl https://my-app.pandastack.io/api/health
curl https://my-app.pandastack.io/api/ready

Your real domain still points to the old environment. No users are affected yet.

Step 2: Mirror Your Database to the New Platform

Use streaming replication or logical replication to keep the new database in sync with the old one in real time:

# Baseline restore
pg_dump   --format=custom   --no-acl   --no-owner   "$OLD_DB_URL" > migration-baseline.dump

pg_restore   --no-acl   --no-owner   -d "$NEW_DB_URL"   migration-baseline.dump

# Enable logical replication on the source
psql "$OLD_DB_URL" -c "CREATE PUBLICATION blue_green_pub FOR ALL TABLES;"
psql "$OLD_DB_URL" -c "SELECT pg_create_logical_replication_slot('blue_green_slot', 'pgoutput');"

# Subscribe on the target
psql "$NEW_DB_URL" -c "
CREATE SUBSCRIPTION blue_green_sub
CONNECTION 'host=old-host dbname=mydb user=replicator password=secret'
PUBLICATION blue_green_pub
WITH (copy_data = false, slot_name = 'blue_green_slot');
"

# Monitor lag until it reaches zero
psql "$OLD_DB_URL" -c "
SELECT pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), confirmed_flush_lsn)) AS lag
FROM pg_replication_slots WHERE slot_name = 'blue_green_slot';
"

Step 3: Run Both Environments Simultaneously

With replication running, your new environment is continuously synced. Now test aggressively against the green URL:

# Run your full integration test suite against the new environment
BASE_URL=https://my-app.pandastack.io npm test

# Load test to verify performance
npx autocannon -d 30 -c 50 https://my-app.pandastack.io/api/products

# Compare response times between old and new
for i in {1..10}; do
  OLD=$(curl -o /dev/null -s -w "%{time_total}" https://old-app.example.com/api/products)
  NEW=$(curl -o /dev/null -s -w "%{time_total}" https://my-app.pandastack.io/api/products)
  echo "Old: ${OLD}s | New: ${NEW}s"
done

Step 4: Gradual Traffic Shift Using DNS Weighted Routing

Many DNS providers support weighted routing. Use it to shift a percentage of traffic to the new environment:

# Example with AWS Route 53 CLI (conceptual — adapt to your DNS provider)
# Start with 10% to new environment
aws route53 change-resource-record-sets --hosted-zone-id YOUR_ZONE_ID   --change-batch '{
    "Changes": [{
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "app.example.com",
        "Type": "CNAME",
        "SetIdentifier": "green",
        "Weight": 10,
        "TTL": 60,
        "ResourceRecords": [{"Value": "my-app.pandastack.io"}]
      }
    }]
  }'

Monitor error rates. If green looks healthy at 10%, increase to 50%, then 100%.

Step 5: The Final Cutover

When you're ready to commit:

# Lower your DNS TTL 24 hours before cutover for faster propagation
# Then update DNS to point fully to PandaStack

# Pause new writes briefly (seconds, not minutes)
# Wait for replication lag = 0
# Update DNS
# Resume traffic
# Verify
curl -I https://app.example.com
curl https://app.example.com/api/health

Step 6: Cleanup

# Drop replication subscription and slot
psql "$NEW_DB_URL" -c "DROP SUBSCRIPTION blue_green_sub;"
psql "$OLD_DB_URL" -c "SELECT pg_drop_replication_slot('blue_green_slot');"
psql "$OLD_DB_URL" -c "DROP PUBLICATION blue_green_pub;"

Keep the old environment running in read-only mode for 48 hours as a safety net, then decommission it. Zero-downtime migration takes more planning than a maintenance window, but your users will never know the difference — which is exactly the point. Visit [docs.pandastack.io](https://docs.pandastack.io) for PandaStack's deployment and database documentation.

Ready to deploy?

Start free on PandaStack — no credit card required.

Start free on PandaStack

More in Guide

Browse all Guide articles →

See also