Database Migration Workflow

Safe schema changes and data migration workflow with rollback strategies and zero-downtime deployment

The Database Migration workflow provides a structured, safe approach to schema changes and data migrations, ensuring data integrity, minimal downtime, and the ability to rollback if issues arise.

Overview#

PropertyValue
Phases4
TierFree
Typical Duration5-6 days
Best ForSchema changes, data transformations, database refactoring

Outcomes#

A successful database migration results in:

  • Migration completed safely with rollback readiness
  • Migration rehearsed in staging environment
  • Rollback procedure tested and documented
  • Data integrity checks passing

Phases#

Phase 1: Schema Design (1 day)#

Agents: database-expert

Design the new schema changes with careful consideration for backward compatibility and data integrity.

Tasks:

  • Document current schema state
  • Design target schema changes
  • Identify breaking vs non-breaking changes
  • Plan for backward compatibility
  • Define data transformation requirements
  • Create migration scripts

Migration Types:

┌────────────────────────────────────────────────────────────┐ │ Migration Types │ ├─────────────────┬──────────────────────────────────────────┤ │ Non-Breaking │ Add column (nullable), add table, │ │ │ add index, expand column type │ ├─────────────────┼──────────────────────────────────────────┤ │ Breaking │ Remove column, rename column, │ │ │ change column type, drop table │ ├─────────────────┼──────────────────────────────────────────┤ │ Data Migration │ Transform existing data, backfill │ │ │ values, merge/split tables │ └─────────────────┴──────────────────────────────────────────┘

Schema Change Example:

1// Before 2model User { 3 id String @id @default(cuid()) 4 name String 5 email String @unique 6 createdAt DateTime @default(now()) 7} 8 9// After - Adding new fields (non-breaking) 10model User { 11 id String @id @default(cuid()) 12 name String 13 email String @unique 14 avatarUrl String? // New nullable field 15 lastLoginAt DateTime? // New nullable field 16 createdAt DateTime @default(now()) 17 updatedAt DateTime @updatedAt // New field with default 18}

Phase 2: Migration Plan (1 day)#

Agents: database-expert, devops-expert

Create a detailed migration plan including timing, rollback procedures, and communication strategy.

Tasks:

  • Define migration window and timing
  • Create step-by-step execution plan
  • Document rollback procedures
  • Plan data validation checks
  • Coordinate with stakeholders
  • Set up monitoring for migration

Migration Plan Template:

1## Migration: [Name] 2**Date:** YYYY-MM-DD 3**Window:** HH:MM - HH:MM (timezone) 4**Risk Level:** Low/Medium/High 5 6### Pre-Migration Checklist 7- [ ] Backup completed and verified 8- [ ] Staging migration successful 9- [ ] Rollback tested 10- [ ] Team notified 11- [ ] Monitoring dashboards open 12 13### Execution Steps 141. Enable maintenance mode (if needed) 152. Take final backup 163. Run migration: `npx prisma migrate deploy` 174. Verify data integrity 185. Run application smoke tests 196. Disable maintenance mode 20 21### Rollback Procedure 221. Enable maintenance mode 232. Restore from backup 243. Revert application code 254. Verify rollback success 265. Disable maintenance mode 27 28### Success Criteria 29- [ ] All migrations applied 30- [ ] Data integrity checks pass 31- [ ] Application functional 32- [ ] No error spikes in monitoring

Phase 3: Implementation (2-3 days)#

Agents: database-expert, backend-expert

Execute the migration with proper staging validation and production deployment.

Tasks:

  • Test migration in development
  • Run migration in staging environment
  • Validate staging data integrity
  • Execute production migration
  • Run data integrity checks
  • Update application code as needed

Prisma Migration Commands:

1# Create migration (development) 2npx prisma migrate dev --name add_user_avatar 3 4# Check migration status 5npx prisma migrate status 6 7# Deploy to production 8npx prisma migrate deploy 9 10# Reset database (development only!) 11npx prisma migrate reset

Zero-Downtime Pattern:

Phase 1: Deploy code that handles both schemas (reads new column, falls back to old) │ ▼ Phase 2: Run migration to add new column │ ▼ Phase 3: Backfill data for new column │ ▼ Phase 4: Deploy code that requires new column │ ▼ Phase 5: Run migration to remove old column

Backfill Script Example:

1// scripts/backfill-avatar-urls.ts 2import { prisma } from '@/lib/prisma'; 3 4async function backfillAvatarUrls() { 5 const batchSize = 1000; 6 let processed = 0; 7 let hasMore = true; 8 9 while (hasMore) { 10 const users = await prisma.user.findMany({ 11 where: { avatarUrl: null }, 12 take: batchSize, 13 select: { id: true, email: true } 14 }); 15 16 if (users.length === 0) { 17 hasMore = false; 18 continue; 19 } 20 21 await prisma.$transaction( 22 users.map(user => 23 prisma.user.update({ 24 where: { id: user.id }, 25 data: { 26 avatarUrl: generateGravatarUrl(user.email) 27 } 28 }) 29 ) 30 ); 31 32 processed += users.length; 33 console.log(`Processed ${processed} users`); 34 } 35 36 console.log('Backfill complete'); 37} 38 39backfillAvatarUrls();

Phase 4: Verification (1 day)#

Agents: testing-expert

Verify the migration was successful and all data integrity requirements are met.

Tasks:

  • Run data integrity checks
  • Verify row counts match expectations
  • Test application functionality
  • Validate API responses
  • Check for data inconsistencies
  • Document migration results

Data Integrity Checks:

1-- Verify row counts 2SELECT 'users' as table_name, COUNT(*) as count FROM users 3UNION ALL 4SELECT 'orders', COUNT(*) FROM orders; 5 6-- Check for orphaned records 7SELECT o.id FROM orders o 8LEFT JOIN users u ON o.user_id = u.id 9WHERE u.id IS NULL; 10 11-- Verify not null constraints 12SELECT COUNT(*) as null_count 13FROM users 14WHERE avatar_url IS NULL AND created_at < '2024-01-01'; 15 16-- Check data consistency 17SELECT id, email FROM users 18WHERE email NOT LIKE '%@%.%';

Starting the Workflow#

1# Start the workflow 2bootspring workflow start database-migration 3 4# Check current status 5bootspring workflow status 6 7# Advance to next phase 8bootspring workflow next 9 10# Mark a checkpoint complete 11bootspring workflow checkpoint "Migration rehearsed"

Completion Signals#

Track progress with these checkpoints:

  1. Migration rehearsed - Successfully tested in staging
  2. Rollback tested - Rollback procedure verified
  3. Data integrity checks passing - All validation queries pass

Best Practices#

Always Have a Backup#

# PostgreSQL backup pg_dump -Fc database_name > backup_$(date +%Y%m%d_%H%M%S).dump # Restore from backup pg_restore -d database_name backup.dump

Use Transactions#

1// Wrap related changes in a transaction 2await prisma.$transaction(async (tx) => { 3 // Create new record 4 const newRecord = await tx.newTable.create({ 5 data: transformedData 6 }); 7 8 // Update reference 9 await tx.oldTable.update({ 10 where: { id: oldRecord.id }, 11 data: { newTableId: newRecord.id } 12 }); 13});

Batch Large Updates#

1// Process large datasets in batches 2const BATCH_SIZE = 1000; 3let skip = 0; 4let hasMore = true; 5 6while (hasMore) { 7 const records = await prisma.record.findMany({ 8 take: BATCH_SIZE, 9 skip, 10 }); 11 12 if (records.length < BATCH_SIZE) { 13 hasMore = false; 14 } 15 16 await processBatch(records); 17 skip += BATCH_SIZE; 18}

Monitor During Migration#

1// Log migration progress 2console.log(`[${new Date().toISOString()}] Starting migration`); 3console.log(`Records to process: ${totalCount}`); 4 5// Track timing 6const startTime = Date.now(); 7// ... migration code ... 8const duration = Date.now() - startTime; 9console.log(`Migration completed in ${duration}ms`);

Tips for Success#

  1. Never skip staging - Always test migrations in a production-like environment
  2. Plan for failure - Have a tested rollback procedure ready
  3. Communicate early - Notify stakeholders about planned downtime
  4. Batch large operations - Avoid long-running transactions
  5. Monitor closely - Watch for errors and performance issues during migration