All articles
Legacy ModernizationDevelopment Tips

Zero-Downtime Database Migrations: A Practical Guide

The Database Migration Challenge

Database migrations are often the riskiest part of application modernization. Unlike application code that can be rolled back instantly, database changes affect persistent state. A failed migration can mean data loss, corruption, or extended downtime.

At Studio X Consulting, we've executed dozens of zero-downtime database migrations. Here are the strategies that work.

Migration Patterns

Pattern 1: Dual-Write Strategy

Write to both old and new databases simultaneously during transition:

  1. Stand up new database alongside old
  2. Replicate existing data
  3. Modify application to write to both databases
  4. Verify data consistency
  5. Switch reads to new database
  6. Stop writing to old database
  7. Decommission old database

Pros: Safe rollback, gradual transition
Cons: Complex application logic, double storage costs

Pattern 2: Blue-Green Database

Maintain two identical environments:

  1. Clone production to "green" environment
  2. Apply schema changes to green
  3. Sync data from blue to green
  4. Switch traffic to green
  5. Keep blue as rollback option

Pros: Fast rollback, clear separation
Cons: Requires double infrastructure, complex data sync

Pattern 3: Expand-Contract (Recommended)

Make backward-compatible changes in phases:

  1. Expand: Add new columns/tables alongside old
  2. Dual-Write: Write to both old and new structures
  3. Migrate Data: Backfill new structures
  4. Switch Reads: Read from new structures
  5. Contract: Remove old columns/tables

Pros: No downtime, safe rollback, minimal risk
Cons: Requires multiple deployments

SQL Server to PostgreSQL Migration

Schema Differences

-- SQL Server
CREATE TABLE users (
  id INT IDENTITY(1,1) PRIMARY KEY,
  created_date DATETIME DEFAULT GETDATE(),
  data NVARCHAR(MAX)
);

-- PostgreSQL equivalent
CREATE TABLE users (
  id SERIAL PRIMARY KEY,
  created_date TIMESTAMPTZ DEFAULT NOW(),
  data TEXT
);

Data Type Mappings

  • NVARCHAR(MAX)TEXT
  • DATETIMETIMESTAMPTZ
  • BITBOOLEAN
  • UNIQUEIDENTIFIERUUID
  • IDENTITYSERIAL or GENERATED ALWAYS AS IDENTITY

Migration Tools

  • pgloader - Automated migration tool, handles most conversions
  • AWS DMS - Managed service for continuous replication
  • Custom Scripts - Python/Node.js for complex transformations

Zero-Downtime Schema Changes

Adding a Column (Safe)

-- Step 1: Add nullable column
ALTER TABLE users ADD COLUMN email VARCHAR(255);

-- Step 2: Backfill data
UPDATE users SET email = legacy_email WHERE email IS NULL;

-- Step 3: Add NOT NULL constraint
ALTER TABLE users ALTER COLUMN email SET NOT NULL;

Renaming a Column (Requires Care)

-- Step 1: Add new column
ALTER TABLE users ADD COLUMN full_name VARCHAR(255);

-- Step 2: Dual-write in application
-- Both old_name and full_name get same value

-- Step 3: Backfill
UPDATE users SET full_name = old_name WHERE full_name IS NULL;

-- Step 4: Switch reads to full_name in application

-- Step 5: Drop old column
ALTER TABLE users DROP COLUMN old_name;

Changing Column Type (Complex)

-- Example: VARCHAR(50) to VARCHAR(255)

-- Step 1: Add new column
ALTER TABLE users ADD COLUMN email_new VARCHAR(255);

-- Step 2: Copy data
UPDATE users SET email_new = email;

-- Step 3: Switch application to use email_new

-- Step 4: Drop old column
ALTER TABLE users DROP COLUMN email;

-- Step 5: Rename new column
ALTER TABLE users RENAME COLUMN email_new TO email;

Data Transformation Strategies

Batch Processing

-- Process in chunks to avoid locking
DO $$
DECLARE
  batch_size INT := 1000;
  offset_val INT := 0;
  rows_affected INT;
BEGIN
  LOOP
    UPDATE users
    SET processed = TRUE
    WHERE id IN (
      SELECT id FROM users
      WHERE processed = FALSE
      ORDER BY id
      LIMIT batch_size
    );

    GET DIAGNOSTICS rows_affected = ROW_COUNT;
    EXIT WHEN rows_affected = 0;

    COMMIT;  -- Release locks between batches
    PERFORM pg_sleep(0.1);  -- Throttle to reduce load
  END LOOP;
END $$;

Background Jobs

For large datasets, use background workers:

  • Queue migration tasks
  • Process during off-peak hours
  • Monitor progress
  • Handle failures gracefully

Testing Strategy

Pre-Migration Checklist

  1. Full Database Backup - Verify backup can be restored
  2. Schema Validation - Compare source and target schemas
  3. Data Validation - Row counts, checksums, sampling
  4. Performance Testing - Query plans on new database
  5. Application Testing - Full regression suite
  6. Rollback Plan - Documented and tested

Validation Queries

-- Row count comparison
SELECT COUNT(*) FROM old_db.users;
SELECT COUNT(*) FROM new_db.users;

-- Data sampling
SELECT * FROM old_db.users ORDER BY RANDOM() LIMIT 100;
SELECT * FROM new_db.users ORDER BY RANDOM() LIMIT 100;

-- Checksum validation (PostgreSQL)
SELECT MD5(CAST(ROW(users.*) AS TEXT))
FROM users ORDER BY id;

Real-World Case Study

We migrated a 500GB SQL Server database to PostgreSQL for a healthcare SaaS company:

Requirements

  • Zero downtime (24/7 operations)
  • No data loss
  • Maintain audit trail
  • Improve query performance

Approach

  1. Week 1-2: Schema mapping and tool evaluation
  2. Week 3-4: Initial data migration using AWS DMS
  3. Week 5-6: Dual-write implementation in application
  4. Week 7: Validation and performance testing
  5. Week 8: Switch reads to PostgreSQL
  6. Week 9: Monitor and optimize
  7. Week 10: Decommission SQL Server

Results

  • Zero downtime - Users experienced no interruption
  • 40% cost reduction - PostgreSQL licensing vs SQL Server
  • 3x faster queries - Better query planner, indexes
  • Simplified operations - Supabase-managed PostgreSQL

Common Pitfalls

  1. Underestimating Data Volume - Test with production-scale data
  2. Ignoring Dependencies - Foreign keys, triggers, stored procedures
  3. No Rollback Plan - Always have a way back
  4. Inadequate Testing - Include edge cases and error scenarios
  5. Poor Communication - Keep stakeholders informed

Tools and Resources

Migration Tools

  • pgloader - PostgreSQL data migration tool
  • AWS DMS - Database Migration Service
  • Flyway - Schema versioning and migration
  • Liquibase - Database-agnostic migrations

Monitoring

  • Track replication lag
  • Monitor query performance
  • Alert on data discrepancies
  • Log all migration operations

Conclusion

Zero-downtime database migrations are challenging but achievable with proper planning, tooling, and execution. The expand-contract pattern combined with comprehensive testing gives you the best chance of success.

Studio X Consulting specializes in complex database migrations. We've helped companies migrate from SQL Server, Oracle, MySQL, and legacy systems to modern platforms like PostgreSQL and Supabase. Let us help you plan and execute your migration with confidence.

Learn more at www.studioxconsulting.com. Contact Studio X Consulting to discuss legacy modernization, AI-assisted development, and delivery.

Keep reading

Related articles