Database DevOps Migrations

Database Migration Best Practices

Safe and reliable strategies for evolving database schemas in production environments

Dhivyan Joseph By Dhivyan Joseph
13 min read

Database Migration Best Practices

Database migrations are one of the most critical and risky aspects of application deployment. A poorly executed migration can bring down your entire system, corrupt data, or create inconsistencies that are difficult to recover from. After managing databases across various scales and technologies, I’ve learned that successful migrations require careful planning, rigorous testing, and defensive programming.

Understanding Migration Fundamentals

What Makes Migrations Risky

Unlike application code changes that can be rolled back instantly, database changes often involve structural modifications that affect existing data. Adding a column is usually safe, but dropping one is irreversible without backups. Changing data types might require transformation logic that could fail on edge cases.

The risk compounds in production environments where:

  • Downtime has real business impact
  • Data volume makes operations slow
  • Multiple application versions might need to work simultaneously
  • Recovery from failures is time-sensitive

Migration Categories

I categorize migrations into three risk levels:

Low Risk (Additive):

  • Adding new tables
  • Adding nullable columns
  • Creating indexes (with proper techniques)
  • Adding constraints that don’t affect existing data

Medium Risk (Transformative):

  • Modifying column types
  • Adding not-null columns with defaults
  • Renaming columns or tables
  • Updating large datasets

High Risk (Destructive):

  • Dropping columns, tables, or indexes
  • Changing primary keys
  • Major structural reorganizations
  • Operations that require exclusive locks

Pre-Migration Planning

Schema Evolution Strategy

Before writing any migration, I establish a clear evolution strategy. This includes understanding:

  • Current application dependencies on the schema
  • How long different application versions need to coexist
  • Rollback requirements and capabilities
  • Performance impact on production workloads

Backup and Recovery Plan

Every migration should have a tested backup and recovery plan. This isn’t just about having backups – it’s about knowing exactly how long recovery takes and practicing the process.

For critical migrations, I create point-in-time backups immediately before execution and verify they’re restorable. I also document the exact steps needed to restore and validate the restoration process.

Testing Strategy

Migration testing requires multiple environments:

Unit Testing: Test migration logic on small datasets with edge cases Integration Testing: Run migrations on production-like data volumes Performance Testing: Measure migration time and system impact Rollback Testing: Verify rollback procedures work correctly

I never run a migration in production that hasn’t been tested on a recent copy of production data.

Safe Migration Techniques

Backwards Compatibility

The safest migrations maintain backwards compatibility with existing application versions. This approach allows for zero-downtime deployments and reduces rollback complexity.

-- Instead of dropping a column immediately
ALTER TABLE users DROP COLUMN old_field;

-- Use a multi-step approach:
-- Step 1: Stop writing to the column (application change)
-- Step 2: Wait for old application versions to be phased out
-- Step 3: Drop the column in a later migration

Column Modifications

Changing column types safely often requires a multi-step process:

-- Unsafe: Direct type change
ALTER TABLE users ALTER COLUMN age TYPE VARCHAR(10);

-- Safe: Multi-step approach
-- Step 1: Add new column
ALTER TABLE users ADD COLUMN age_varchar VARCHAR(10);

-- Step 2: Populate new column
UPDATE users SET age_varchar = age::VARCHAR;

-- Step 3: Update application to use new column
-- Step 4: Drop old column in later migration

Large Data Operations

Operations on large datasets need special handling to avoid long-running transactions:

-- Unsafe: Single large update
UPDATE orders SET status = 'processed' WHERE created_at < '2023-01-01';

-- Safe: Batch processing
DO $$
DECLARE
    batch_size INTEGER := 1000;
    updated_count INTEGER;
BEGIN
    LOOP
        UPDATE orders
        SET status = 'processed'
        WHERE id IN (
            SELECT id FROM orders
            WHERE created_at < '2023-01-01'
            AND status != 'processed'
            LIMIT batch_size
        );

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

        -- Brief pause between batches
        PERFORM pg_sleep(0.1);
    END LOOP;
END $$;

Index Management

Online Index Creation

Creating indexes on large tables can lock them for extended periods. Modern databases offer online index creation, but it still requires careful timing:

-- PostgreSQL online index creation
CREATE INDEX CONCURRENTLY idx_users_email ON users(email);

-- Monitor progress
SELECT
    now()::TIME,
    query,
    state,
    waiting
FROM pg_stat_activity
WHERE query LIKE '%CREATE INDEX%';

Index Drops and Recreations

Dropping indexes is generally safe and fast, but recreating them takes time. I often schedule index recreations during low-traffic periods and monitor application performance during the process.

Database-Specific Considerations

PostgreSQL Migrations

PostgreSQL’s strong consistency guarantees make some operations safer but potentially slower:

  • Use CONCURRENTLY for index operations when possible
  • Leverage ADD COLUMN with defaults efficiently (newer versions optimize this)
  • Be aware of lock escalation in long transactions

MySQL Migrations

MySQL has different locking behaviors and capabilities:

  • Online DDL capabilities vary by operation and version
  • pt-online-schema-change from Percona Toolkit helps with large table modifications
  • Be mindful of replication lag during large operations

NoSQL Considerations

Document databases require different migration strategies:

  • Schema-on-read approaches allow for gradual migrations
  • Consider field presence checks in application code
  • Plan for mixed document structures during transitions

Monitoring and Observability

Migration Metrics

I track several metrics during migrations:

  • Execution time and progress
  • Database performance impact
  • Application error rates
  • Replication lag (in replicated systems)

Alerting Strategy

Set up alerts for:

  • Migration failures or timeouts
  • Unusual database performance patterns
  • Application errors that might be migration-related
  • Long-running transactions that exceed expected duration

Rollback Triggers

Define clear criteria for triggering rollbacks:

  • Migration exceeds expected time by X%
  • Application error rates increase beyond threshold
  • Database performance degrades significantly
  • Manual intervention required

Team Coordination

Communication Protocols

Large migrations require coordination across teams:

  • Pre-migration briefings with all stakeholders
  • Real-time communication channels during execution
  • Clear escalation procedures for issues
  • Post-migration review and documentation

Change Management

Implement approval processes for high-risk migrations:

  • Peer review of migration scripts
  • Database administrator approval for structural changes
  • Staging environment validation requirements
  • Production deployment scheduling

Automation and Tooling

Migration Frameworks

Use migration frameworks that provide:

  • Version control integration
  • Rollback capabilities
  • State tracking and validation
  • Batch processing utilities

CI/CD Integration

Integrate migrations into deployment pipelines with:

  • Automated testing on representative datasets
  • Deployment ordering that considers migration dependencies
  • Automated rollback triggers for failed deployments

Custom Tooling

Develop custom tools for common patterns:

  • Large table modification utilities
  • Migration progress monitoring
  • Automated backup and verification scripts

Recovery and Incident Response

Failed Migration Response

When migrations fail:

  1. Stop immediately – don’t try to “fix forward” without assessment
  2. Assess impact – what’s broken and how badly
  3. Communicate status – keep stakeholders informed
  4. Execute recovery plan – follow pre-planned recovery procedures
  5. Post-incident review – learn from the failure

Data Consistency Validation

After any migration:

  • Run consistency checks to validate data integrity
  • Compare record counts and key metrics before/after
  • Verify application functionality end-to-end
  • Monitor for delayed issues that might surface later

Long-term Migration Strategy

Technical Debt Management

Successful migrations often create technical debt:

  • Old columns that need eventual cleanup
  • Temporary indexes that serve transition periods
  • Application code that handles multiple schema versions

Plan for debt retirement as part of your migration strategy.

Documentation and Knowledge Transfer

Maintain comprehensive documentation:

  • Migration rationale and decision history
  • Known issues and workarounds
  • Recovery procedures and contact information
  • Performance characteristics and optimization opportunities

Conclusion

Database migrations are high-stakes operations that require respect, planning, and defensive programming. The techniques that work for small applications don’t necessarily scale to production systems with millions of records and strict uptime requirements.

Success comes from combining careful planning, rigorous testing, and conservative execution strategies. While it’s tempting to take shortcuts when deadlines loom, the potential cost of migration failures far exceeds the time invested in doing them properly.

The best migration is one that’s so well-planned and executed that it’s invisible to users and operators alike. Invest in the tools, processes, and expertise needed to make your database evolution as smooth and reliable as your application deployments.

Database DevOps Migrations

Stay Updated

Get notified about new posts.

Unsubscribe at any time. Read the privacy policy.