managing-database-migrations

Managing Database Migrations

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "managing-database-migrations" with this command: npx skills add doanchienthangdev/omgkit/doanchienthangdev-omgkit-managing-database-migrations

Managing Database Migrations

Purpose

Implement safe, reversible database migrations for production environments:

  • Apply expand-contract pattern for zero-downtime changes

  • Design rollback strategies for every migration

  • Handle large table alterations safely

  • Integrate migrations with CI/CD pipelines

  • Test migrations before production deployment

Quick Start

Prisma

npx prisma migrate dev --name add_user_roles npx prisma migrate deploy # Production

TypeORM

npm run typeorm migration:generate -- -n AddUserRoles npm run typeorm migration:run

Raw SQL with naming convention

migrations/20241230_001_add_user_roles.sql

// Prisma migration example // prisma/migrations/20241230_add_user_roles/migration.sql ALTER TABLE "users" ADD COLUMN "role" VARCHAR(50) DEFAULT 'user'; CREATE INDEX "idx_users_role" ON "users"("role");

Features

Feature Strategy When to Use

Add Column Add nullable, then backfill, then NOT NULL Always safe

Remove Column Stop using, deploy, then remove Expand-contract

Rename Column Add new, copy data, remove old Zero-downtime required

Change Type Add new column, migrate, swap Data transformation

Add Index CREATE CONCURRENTLY Large tables (>1M rows)

Drop Table Rename first, drop after verification Reversible delete

Common Patterns

Expand-Contract Pattern

-- EXPAND: Add new structure (backward compatible) -- Migration 1: Add new column ALTER TABLE users ADD COLUMN full_name VARCHAR(255);

-- Application: Write to BOTH columns UPDATE users SET full_name = first_name || ' ' || last_name;

-- Deploy application that reads from new column

-- CONTRACT: Remove old structure -- Migration 2: (after app deployed) ALTER TABLE users DROP COLUMN first_name; ALTER TABLE users DROP COLUMN last_name;

Safe Column Addition

-- Step 1: Add nullable column ALTER TABLE orders ADD COLUMN shipping_method VARCHAR(50);

-- Step 2: Backfill in batches (avoid locking) UPDATE orders SET shipping_method = 'standard' WHERE id IN (SELECT id FROM orders WHERE shipping_method IS NULL LIMIT 10000);

-- Step 3: Add NOT NULL constraint ALTER TABLE orders ALTER COLUMN shipping_method SET NOT NULL; ALTER TABLE orders ALTER COLUMN shipping_method SET DEFAULT 'standard';

Safe Column Removal

-- Step 1: Stop application from using column -- (Deploy code that no longer reads/writes to column)

-- Step 2: Drop default and constraints ALTER TABLE users ALTER COLUMN legacy_field DROP DEFAULT; ALTER TABLE users ALTER COLUMN legacy_field DROP NOT NULL;

-- Step 3: Remove column (after verification period) ALTER TABLE users DROP COLUMN legacy_field;

Safe Index Creation (Large Tables)

-- WRONG: Locks table for duration CREATE INDEX idx_orders_status ON orders(status);

-- CORRECT: Non-blocking for PostgreSQL CREATE INDEX CONCURRENTLY idx_orders_status ON orders(status);

-- Note: CONCURRENTLY cannot run in transaction -- For Prisma, use raw SQL migration: -- prisma/migrations/xxx/migration.sql -- /* Disable transaction for this migration */ CREATE INDEX CONCURRENTLY idx_orders_status ON orders(status);

Prisma Migration Workflow

Development: Create and apply migration

npx prisma migrate dev --name add_user_roles

Preview SQL without applying

npx prisma migrate diff
--from-schema-datamodel prisma/schema.prisma
--to-schema-datamodel prisma/schema.prisma.new
--script

Production deployment

npx prisma migrate deploy

Reset for development (DESTRUCTIVE)

npx prisma migrate reset

// schema.prisma - Example with relations model User { id String @id @default(uuid()) email String @unique role Role @default(USER) posts Post[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt

@@index([email]) }

enum Role { USER ADMIN }

TypeORM Migration

// migrations/1703936400000-AddUserRoles.ts import { MigrationInterface, QueryRunner } from 'typeorm';

export class AddUserRoles1703936400000 implements MigrationInterface { public async up(queryRunner: QueryRunner): Promise<void> { await queryRunner.query( ALTER TABLE "users" ADD COLUMN "role" VARCHAR(50) DEFAULT 'user' ); await queryRunner.query( CREATE INDEX "idx_users_role" ON "users"("role") ); }

public async down(queryRunner: QueryRunner): Promise<void> { await queryRunner.query(DROP INDEX "idx_users_role"); await queryRunner.query(ALTER TABLE "users" DROP COLUMN "role"); } }

Data Migration Pattern

// Separate data migration from schema migration export class MigrateUserNames1703936500000 implements MigrationInterface { public async up(queryRunner: QueryRunner): Promise<void> { // Batch process to avoid memory issues const batchSize = 1000; let offset = 0;

while (true) {
  const result = await queryRunner.query(`
    UPDATE users
    SET full_name = first_name || ' ' || last_name
    WHERE full_name IS NULL
    LIMIT ${batchSize}
  `);

  if (result.affectedRows === 0) break;
  offset += batchSize;

  // Optional: Add delay to reduce load
  await new Promise(r => setTimeout(r, 100));
}

}

public async down(queryRunner: QueryRunner): Promise<void> { // Data migrations often aren't reversible console.log('Data migration rollback: manual intervention required'); } }

Use Cases

  • Adding new features requiring schema changes

  • Refactoring database structure safely

  • Splitting or merging tables

  • Changing column data types

  • Large-scale data migrations

Best Practices

Do Avoid

Test migrations on production-like data Testing only on empty databases

Use expand-contract for breaking changes Direct column renames in production

Create CONCURRENTLY for large table indexes Blocking index creation on live tables

Batch large data updates Updating millions of rows in one transaction

Include rollback in every migration Forward-only migrations without escape

Run migrations in CI before deploy Manual migration execution

Version control all migrations Modifying applied migrations

Separate schema and data migrations Mixing DDL and large DML in one migration

Migration Checklist

Pre-Migration: [ ] Migration tested on staging with production data volume [ ] Rollback script written and tested [ ] Estimated execution time documented [ ] Backup verified

During Migration: [ ] Monitor database locks and connections [ ] Check application error rates [ ] Verify migration progress

Post-Migration: [ ] Verify data integrity [ ] Check application functionality [ ] Monitor performance metrics [ ] Document completion

CI/CD Integration

GitHub Actions example

  • name: Run Migrations run: |

    Wait for healthy database

    until pg_isready -h $DB_HOST; do sleep 1; done

    Run migrations with timeout

    timeout 600 npx prisma migrate deploy

    Verify migration status

    npx prisma migrate status env: DATABASE_URL: ${{ secrets.DATABASE_URL }}

Related Skills

See also these related skill documents:

  • designing-database-schemas - Schema design principles

  • managing-databases - DBA operations and maintenance

  • optimizing-databases - Performance tuning

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

database-optimization

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

postgresql

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

building-nestjs-apis

No summary provided by upstream source.

Repository SourceNeeds Review