Source profileQuality 72/100Review permissions

affaan-m/ECC/docs/es/skills/database-migrations/SKILL.md

database-migrations

Buenas prácticas de migración de base de datos para cambios de esquema, migraciones de datos, rollbacks y despliegues de tiempo cero en PostgreSQL, MySQL y ORMs comunes (Prisma, Drizzle, Kysely, Django, TypeORM, golang-migrate).

Source repository stars
234,327
Declared platforms
0
Static risk flags
1
Last source update
2026-07-27
Source checked
2026-07-28

Decision brief

What it does—and where it fits

Cambios de esquema de base de datos seguros y reversibles para sistemas de producción.

Best for

    Not for

    • Tasks that require unconfirmed production actions or broad system permissions.
    • Environments where the pinned source and install steps cannot be inspected.

    Compatibility matrix

    Platform support, with evidence labels

    PlatformStatusEvidenceWhat to check
    CodexNot declaredNo explicit evidencePortability before use
    Claude CodeNot declaredNo explicit evidencePortability before use
    CursorNot declaredNo explicit evidencePortability before use
    Gemini CLINot declaredNo explicit evidencePortability before use
    Open the compatibility checker

    Installation

    Inspect first. Install second.

    The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

    Source-detected install commandSource
    npx skills add https://github.com/affaan-m/ECC --skill "docs/es/skills/database-migrations"
    Safe inspection promptEditorial

    Inspect the Agent Skill "database-migrations" from https://github.com/affaan-m/ECC/blob/4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38/docs/es/skills/database-migrations/SKILL.md at commit 4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

    Workflow

    What the source asks the agent to do

    1. 01

      Cuándo Activar

      Crear o alterar tablas de base de datos

      Crear o alterar tablas de base de datosAgregar/eliminar columnas o índicesEjecutar migraciones de datos (backfill, transformación)
    2. 02

      Principios Fundamentales

      1. Cada cambio es una migración — nunca alterar bases de datos de producción manualmente 2. Las migraciones son solo hacia adelante en producción — los rollbacks usan nuevas migraciones hacia adelante 3. Las migraciones de esquema y de datos son separadas — nunca mezclar DDL y D…

      Cada cambio es una migración — nunca alterar bases de datos de producción manualmenteLas migraciones son solo hacia adelante en producción — los rollbacks usan nuevas migraciones hacia adelanteLas migraciones de esquema y de datos son separadas — nunca mezclar DDL y DML en una migración
    3. 03

      Lista de Verificación de Seguridad de Migración

      Antes de aplicar cualquier migración:

      [ ] La migración tiene tanto UP como DOWN (o está marcada explícitamente como irreversible)[ ] Sin bloqueos de tabla completa en tablas grandes (usar operaciones concurrentes)[ ] Las nuevas columnas tienen valores predeterminados o son nullable (nunca agregar NOT NULL sin valor predeterminado)
    4. 04

      Patrones PostgreSQL

      Nunca renombrar directamente en producción. Usar el patrón expand-contract:

      Nunca renombrar directamente en producción. Usar el patrón expand-contract:
    5. 05

      Agregar una Columna de Forma Segura

      Review the “Agregar una Columna de Forma Segura” section in the pinned source before continuing.

      Review and apply the “Agregar una Columna de Forma Segura” source section.

    Permission review

    Static risk signals and limitations

    Runs scripts

    medium · line 127

    The documentation asks the agent to run terminal commands or scripts.

    npx prisma migrate dev --name add_user_avatar

    Runs scripts

    medium · line 130

    The documentation asks the agent to run terminal commands or scripts.

    npx prisma migrate deploy

    Evidence record

    Why each signal appears

    EvidenceSourceComputedTestedEditorial
    SignalValueEvidence typeMeaning
    Quality score72/100ComputedDocumentation, specificity, maintenance, and trust rules
    Repository stars234,327SourceRepository attention, not individual Skill quality
    Compatibility0 platformsSourceDeclared in the catalog source record
    Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

    Pinned source

    Provenance and original SKILL.md

    Repository
    affaan-m/ECC
    Skill path
    docs/es/skills/database-migrations/SKILL.md
    Commit
    4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38
    License
    MIT
    Collected
    2026-07-28
    Default branch
    main
    View the original SKILL.md

    Patrones de Migración de Base de Datos

    Cambios de esquema de base de datos seguros y reversibles para sistemas de producción.

    Cuándo Activar

    • Crear o alterar tablas de base de datos
    • Agregar/eliminar columnas o índices
    • Ejecutar migraciones de datos (backfill, transformación)
    • Planificar cambios de esquema de tiempo cero (zero-downtime)
    • Configurar herramientas de migración para un nuevo proyecto

    Principios Fundamentales

    1. Cada cambio es una migración — nunca alterar bases de datos de producción manualmente
    2. Las migraciones son solo hacia adelante en producción — los rollbacks usan nuevas migraciones hacia adelante
    3. Las migraciones de esquema y de datos son separadas — nunca mezclar DDL y DML en una migración
    4. Probar migraciones contra datos de tamaño de producción — una migración que funciona en 100 filas puede bloquear en 10M
    5. Las migraciones son inmutables una vez desplegadas — nunca editar una migración que ya se ejecutó en producción

    Lista de Verificación de Seguridad de Migración

    Antes de aplicar cualquier migración:

    • La migración tiene tanto UP como DOWN (o está marcada explícitamente como irreversible)
    • Sin bloqueos de tabla completa en tablas grandes (usar operaciones concurrentes)
    • Las nuevas columnas tienen valores predeterminados o son nullable (nunca agregar NOT NULL sin valor predeterminado)
    • Índices creados de forma concurrente (no en línea con CREATE TABLE para tablas existentes)
    • El backfill de datos es una migración separada del cambio de esquema
    • Probado contra una copia de datos de producción
    • Plan de rollback documentado

    Patrones PostgreSQL

    Agregar una Columna de Forma Segura

    -- BIEN: Columna nullable, sin bloqueo
    ALTER TABLE users ADD COLUMN avatar_url TEXT;
    
    -- BIEN: Columna con valor predeterminado (Postgres 11+ es instantáneo, sin reescritura)
    ALTER TABLE users ADD COLUMN is_active BOOLEAN NOT NULL DEFAULT true;
    
    -- MAL: NOT NULL sin valor predeterminado en tabla existente (requiere reescritura completa)
    ALTER TABLE users ADD COLUMN role TEXT NOT NULL;
    -- Esto bloquea la tabla y reescribe cada fila
    

    Agregar un Índice Sin Tiempo de Inactividad

    -- MAL: Bloquea escrituras en tablas grandes
    CREATE INDEX idx_users_email ON users (email);
    
    -- BIEN: No bloqueante, permite escrituras concurrentes
    CREATE INDEX CONCURRENTLY idx_users_email ON users (email);
    
    -- Nota: CONCURRENTLY no puede ejecutarse dentro de un bloque de transacción
    -- La mayoría de herramientas de migración necesitan manejo especial para esto
    

    Renombrar una Columna (Zero-Downtime)

    Nunca renombrar directamente en producción. Usar el patrón expand-contract:

    -- Paso 1: Agregar nueva columna (migración 001)
    ALTER TABLE users ADD COLUMN display_name TEXT;
    
    -- Paso 2: Backfill de datos (migración 002, migración de datos)
    UPDATE users SET display_name = username WHERE display_name IS NULL;
    
    -- Paso 3: Actualizar el código de la aplicación para leer/escribir ambas columnas
    -- Desplegar cambios de aplicación
    
    -- Paso 4: Dejar de escribir en la columna antigua, eliminarla (migración 003)
    ALTER TABLE users DROP COLUMN username;
    

    Eliminar una Columna de Forma Segura

    -- Paso 1: Eliminar todas las referencias de la aplicación a la columna
    -- Paso 2: Desplegar la aplicación sin la referencia a la columna
    -- Paso 3: Eliminar la columna en la próxima migración
    ALTER TABLE orders DROP COLUMN legacy_status;
    
    -- Para Django: usar SeparateDatabaseAndState para eliminar del modelo
    -- sin generar DROP COLUMN (luego eliminar en la próxima migración)
    

    Migraciones de Datos Grandes

    -- MAL: Actualiza todas las filas en una transacción (bloquea la tabla)
    UPDATE users SET normalized_email = LOWER(email);
    
    -- BIEN: Actualización en lotes con progreso
    DO $$
    DECLARE
      batch_size INT := 10000;
      rows_updated INT;
    BEGIN
      LOOP
        UPDATE users
        SET normalized_email = LOWER(email)
        WHERE id IN (
          SELECT id FROM users
          WHERE normalized_email IS NULL
          LIMIT batch_size
          FOR UPDATE SKIP LOCKED
        );
        GET DIAGNOSTICS rows_updated = ROW_COUNT;
        RAISE NOTICE 'Updated % rows', rows_updated;
        EXIT WHEN rows_updated = 0;
        COMMIT;
      END LOOP;
    END $$;
    

    Prisma (TypeScript/Node.js)

    Flujo de Trabajo

    # Crear migración a partir de cambios de esquema
    npx prisma migrate dev --name add_user_avatar
    
    # Aplicar migraciones pendientes en producción
    npx prisma migrate deploy
    
    # Resetear base de datos (solo desarrollo)
    npx prisma migrate reset
    
    # Generar cliente después de cambios de esquema
    npx prisma generate
    

    Ejemplo de Esquema

    model User {
      id        String   @id @default(cuid())
      email     String   @unique
      name      String?
      avatarUrl String?  @map("avatar_url")
      createdAt DateTime @default(now()) @map("created_at")
      updatedAt DateTime @updatedAt @map("updated_at")
      orders    Order[]
    
      @@map("users")
      @@index([email])
    }
    

    Migración SQL Personalizada

    Para operaciones que Prisma no puede expresar (índices concurrentes, backfills de datos):

    # Crear migración vacía, luego editar el SQL manualmente
    npx prisma migrate dev --create-only --name add_email_index
    
    -- migrations/20240115_add_email_index/migration.sql
    -- Prisma no puede generar CONCURRENTLY, por lo que se escribe manualmente
    CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_users_email ON users (email);
    

    Drizzle (TypeScript/Node.js)

    Flujo de Trabajo

    # Generar migración a partir de cambios de esquema
    npx drizzle-kit generate
    
    # Aplicar migraciones
    npx drizzle-kit migrate
    
    # Hacer push del esquema directamente (solo desarrollo, sin archivo de migración)
    npx drizzle-kit push
    

    Ejemplo de Esquema

    import { pgTable, text, timestamp, uuid, boolean } from "drizzle-orm/pg-core";
    
    export const users = pgTable("users", {
      id: uuid("id").primaryKey().defaultRandom(),
      email: text("email").notNull().unique(),
      name: text("name"),
      isActive: boolean("is_active").notNull().default(true),
      createdAt: timestamp("created_at").notNull().defaultNow(),
      updatedAt: timestamp("updated_at").notNull().defaultNow(),
    });
    

    Kysely (TypeScript/Node.js)

    Flujo de Trabajo (kysely-ctl)

    # Inicializar archivo de configuración (kysely.config.ts)
    kysely init
    
    # Crear un nuevo archivo de migración
    kysely migrate make add_user_avatar
    
    # Aplicar todas las migraciones pendientes
    kysely migrate latest
    
    # Revertir la última migración
    kysely migrate down
    
    # Mostrar estado de migraciones
    kysely migrate list
    

    Archivo de Migración

    // migrations/2024_01_15_001_create_user_profile.ts
    import { type Kysely, sql } from 'kysely'
    
    // IMPORTANTE: Siempre usar Kysely<any>, no tu interfaz de DB tipada.
    // Las migraciones están congeladas en el tiempo y no deben depender de los tipos de esquema actuales.
    export async function up(db: Kysely<any>): Promise<void> {
      await db.schema
        .createTable('user_profile')
        .addColumn('id', 'serial', (col) => col.primaryKey())
        .addColumn('email', 'varchar(255)', (col) => col.notNull().unique())
        .addColumn('avatar_url', 'text')
        .addColumn('created_at', 'timestamp', (col) =>
          col.defaultTo(sql`now()`).notNull()
        )
        .execute()
    
      await db.schema
        .createIndex('idx_user_profile_avatar')
        .on('user_profile')
        .column('avatar_url')
        .execute()
    }
    
    export async function down(db: Kysely<any>): Promise<void> {
      await db.schema.dropTable('user_profile').execute()
    }
    

    Migrador Programático

    import { Migrator, FileMigrationProvider } from 'kysely'
    import { promises as fs } from 'fs'
    import * as path from 'path'
    // Solo ESM — CJS puede usar __dirname directamente
    import { fileURLToPath } from 'url'
    const migrationFolder = path.join(
      path.dirname(fileURLToPath(import.meta.url)),
      './migrations',
    )
    
    // `db` es tu instancia de base de datos Kysely<any>
    const migrator = new Migrator({
      db,
      provider: new FileMigrationProvider({
        fs,
        path,
        migrationFolder,
      }),
      // ADVERTENCIA: Solo habilitar en desarrollo. Deshabilita la validación de
      // ordenamiento por timestamp, lo que puede causar deriva de esquema entre entornos.
      // allowUnorderedMigrations: true,
    })
    
    const { error, results } = await migrator.migrateToLatest()
    
    results?.forEach((it) => {
      if (it.status === 'Success') {
        console.log(`migration "${it.migrationName}" executed successfully`)
      } else if (it.status === 'Error') {
        console.error(`failed to execute migration "${it.migrationName}"`)
      }
    })
    
    if (error) {
      console.error('migration failed', error)
      process.exit(1)
    }
    

    Django (Python)

    Flujo de Trabajo

    # Generar migración a partir de cambios de modelo
    python manage.py makemigrations
    
    # Aplicar migraciones
    python manage.py migrate
    
    # Mostrar estado de migraciones
    python manage.py showmigrations
    
    # Generar migración vacía para SQL personalizado
    python manage.py makemigrations --empty app_name -n description
    

    Migración de Datos

    from django.db import migrations
    
    def backfill_display_names(apps, schema_editor):
        User = apps.get_model("accounts", "User")
        batch_size = 5000
        users = User.objects.filter(display_name="")
        while users.exists():
            batch = list(users[:batch_size])
            for user in batch:
                user.display_name = user.username
            User.objects.bulk_update(batch, ["display_name"], batch_size=batch_size)
    
    def reverse_backfill(apps, schema_editor):
        pass  # Migración de datos, no se necesita reversión
    
    class Migration(migrations.Migration):
        dependencies = [("accounts", "0015_add_display_name")]
    
        operations = [
            migrations.RunPython(backfill_display_names, reverse_backfill),
        ]
    

    SeparateDatabaseAndState

    Eliminar una columna del modelo Django sin eliminarla de la base de datos inmediatamente:

    class Migration(migrations.Migration):
        operations = [
            migrations.SeparateDatabaseAndState(
                state_operations=[
                    migrations.RemoveField(model_name="user", name="legacy_field"),
                ],
                database_operations=[],  # No tocar la DB todavía
            ),
        ]
    

    golang-migrate (Go)

    Flujo de Trabajo

    # Crear par de migración
    migrate create -ext sql -dir migrations -seq add_user_avatar
    
    # Aplicar todas las migraciones pendientes
    migrate -path migrations -database "$DATABASE_URL" up
    
    # Revertir la última migración
    migrate -path migrations -database "$DATABASE_URL" down 1
    
    # Forzar versión (corregir estado sucio)
    migrate -path migrations -database "$DATABASE_URL" force VERSION
    

    Archivos de Migración

    -- migrations/000003_add_user_avatar.up.sql
    ALTER TABLE users ADD COLUMN avatar_url TEXT;
    CREATE INDEX CONCURRENTLY idx_users_avatar ON users (avatar_url) WHERE avatar_url IS NOT NULL;
    
    -- migrations/000003_add_user_avatar.down.sql
    DROP INDEX IF EXISTS idx_users_avatar;
    ALTER TABLE users DROP COLUMN IF EXISTS avatar_url;
    

    Estrategia de Migración de Zero-Downtime

    Para cambios críticos de producción, seguir el patrón expand-contract:

    Fase 1: EXPAND (Expandir)
      - Agregar nueva columna/tabla (nullable o con valor predeterminado)
      - Desplegar: la app escribe en AMBAS, vieja y nueva
      - Backfill de datos existentes
    
    Fase 2: MIGRATE (Migrar)
      - Desplegar: la app lee de la NUEVA, escribe en AMBAS
      - Verificar consistencia de datos
    
    Fase 3: CONTRACT (Contraer)
      - Desplegar: la app solo usa la NUEVA
      - Eliminar columna/tabla antigua en migración separada
    

    Ejemplo de Línea de Tiempo

    Día 1: Migración agrega columna new_status (nullable)
    Día 1: Desplegar app v2 — escribe en status y new_status
    Día 2: Ejecutar migración de backfill para filas existentes
    Día 3: Desplegar app v3 — lee solo de new_status
    Día 7: Migración elimina columna status antigua
    

    Anti-Patrones

    Anti-PatrónPor Qué FallaMejor Enfoque
    SQL manual en producciónSin historial de auditoría, no repetibleSiempre usar archivos de migración
    Editar migraciones desplegadasCausa deriva entre entornosCrear nueva migración en su lugar
    NOT NULL sin valor predeterminadoBloquea tabla, reescribe todas las filasAgregar nullable, backfill, luego agregar restricción
    Índice en línea en tabla grandeBloquea escrituras durante la construcciónCREATE INDEX CONCURRENTLY
    Esquema + datos en una migraciónDifícil de revertir, transacciones largasMigraciones separadas
    Eliminar columna antes de eliminar códigoErrores de aplicación por columna faltanteEliminar código primero, eliminar columna en el próximo despliegue

    Alternatives

    Compare before choosing