Communitygithub.com

database-migrations

Bonnes pratiques de migration de base de données : modifications de schéma, migrations de données, rollbacks et déploiements sans interruption pour PostgreSQL, MySQL et les ORMs courants (Prisma, Drizzle, Kysely, Django, TypeORM, golang-migrate).

Qu'est-ce que database-migrations ?

Ce skill fournit un ensemble complet de bonnes pratiques pour les migrations de bases de données, couvrant les schémas, les données et les déploiements sans interruption. Il est conçu pour être activé lors de la création ou la modification de tables, l'ajout/suppression de colonnes ou d'index, le backfill de données, ou la planification de déploiements zero-downtime. Le skill prend en charge PostgreSQL, MySQL et les principaux ORMs et frameworks comme Prisma, Drizzle, Kysely, Django, TypeORM et golang-migrate. Il inclut des patrons détaillés comme "expand-contract" pour les changements de schéma sans interruption, des checklists de sécurité, et des exemples concrets pour chaque outil, avec des conseils pour éviter les pièges courants comme les verrous de table ou les migrations non réversibles.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/everything-claude-code/tree/main/skills/database-migrations

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Modèles de Migration de Base de Données

Modifications de schéma de base de données sûres et réversibles pour les systèmes de production.

Quand Activer

  • Création ou modification de tables de base de données
  • Ajout/suppression de colonnes ou d'index
  • Exécution de migrations de données (backfill, transformation)
  • Planification de changements de schéma sans interruption
  • Mise en place d'outils de migration pour un nouveau projet

Principes Fondamentaux

  1. Chaque changement est une migration — ne jamais modifier manuellement une base de production
  2. Les migrations sont unidirectionnelles en production — les rollbacks utilisent de nouvelles migrations
  3. Les migrations de schéma et de données sont séparées — ne jamais mélanger DDL et DML dans une même migration
  4. Tester les migrations avec des données de taille production — une migration qui fonctionne sur 100 lignes peut bloquer sur 10M
  5. Les migrations sont immuables une fois déployées — ne jamais modifier une migration qui a été exécutée en production

Checklist de Sécurité des Migrations

Avant d'appliquer une migration :

  • La migration a UP et DOWN (ou est explicitement marquée comme irréversible)
  • Pas de verrous de table complets sur les grandes tables (utiliser des opérations concurrentes)
  • Les nouvelles colonnes ont des valeurs par défaut ou sont nullables (ne jamais ajouter NOT NULL sans valeur par défaut)
  • Les index créés de manière concurrente (pas en ligne avec CREATE TABLE pour les tables existantes)
  • Le backfill de données est une migration séparée du changement de schéma
  • Testé sur une copie des données de production
  • Plan de rollback documenté

Modèles PostgreSQL

Ajout d'une Colonne en Toute Sécurité

-- BON : Colonne nullable, pas de verrou
ALTER TABLE users ADD COLUMN avatar_url TEXT;

-- BON : Colonne avec valeur par défaut (Postgres 11+, instantané, pas de réécriture)
ALTER TABLE users ADD COLUMN is_active BOOLEAN NOT NULL DEFAULT true;

-- MAUVAIS : NOT NULL sans valeur par défaut sur une table existante (nécessite une réécriture complète)
ALTER TABLE users ADD COLUMN role TEXT NOT NULL;
-- Cela verrouille la table et réécrit chaque ligne

Ajout d'un Index Sans Interruption

-- MAUVAIS : Bloque les écritures sur les grandes tables
CREATE INDEX idx_users_email ON users (email);

-- BON : Non bloquant, permet les écritures concurrentes
CREATE INDEX CONCURRENTLY idx_users_email ON users (email);

-- Note : CONCURRENTLY ne peut pas être exécuté dans un bloc de transaction
-- La plupart des outils de migration nécessitent une gestion spéciale pour cela

Renommer une Colonne (Zéro Interruption)

Ne jamais renommer directement en production. Utiliser le modèle expand-contract :

-- Étape 1 : Ajouter la nouvelle colonne (migration 001)
ALTER TABLE users ADD COLUMN display_name TEXT;

-- Étape 2 : Backfill des données (migration 002, migration de données)
UPDATE users SET display_name = username WHERE display_name IS NULL;

-- Étape 3 : Mettre à jour le code de l'application pour lire/écrire les deux colonnes
-- Déployer les modifications de l'application

-- Étape 4 : Arrêter d'écrire dans l'ancienne colonne, la supprimer (migration 003)
ALTER TABLE users DROP COLUMN username;

Suppression Sécurisée d'une Colonne

-- Étape 1 : Supprimer toutes les références à la colonne dans l'application
-- Étape 2 : Déployer l'application sans la référence à la colonne
-- Étape 3 : Supprimer la colonne dans la migration suivante
ALTER TABLE orders DROP COLUMN legacy_status;

-- Pour Django : utiliser SeparateDatabaseAndState pour supprimer du modèle
-- sans générer DROP COLUMN (puis supprimer dans la migration suivante)

Migrations de Données Volumineuses

-- MAUVAIS : Met à jour toutes les lignes dans une seule transaction (verrouille la table)
UPDATE users SET normalized_email = LOWER(email);

-- BON : Mise à jour par lots avec suivi de progression
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 'Lignes mises à jour : %', rows_updated;
    EXIT WHEN rows_updated = 0;
    COMMIT;
  END LOOP;
END $$;

Prisma (TypeScript/Node.js)

Workflow

# Créer une migration à partir des modifications de schéma
npx prisma migrate dev --name add_user_avatar

# Appliquer les migrations en attente en production
npx prisma migrate deploy

# Réinitialiser la base de données (développement uniquement)
npx prisma migrate reset

# Générer le client après les modifications de schéma
npx prisma generate

Exemple de Schéma

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])
}

Migration SQL Personnalisée

Pour les opérations que Prisma ne peut pas exprimer (index concurrents, backfills de données) :

# Créer une migration vide, puis éditer le SQL manuellement
npx prisma migrate dev --create-only --name add_email_index
-- migrations/20240115_add_email_index/migration.sql
-- Prisma ne peut pas générer CONCURRENTLY, donc nous l'écrivons manuellement
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_users_email ON users (email);

Drizzle (TypeScript/Node.js)

Workflow

# Générer la migration à partir des modifications de schéma
npx drizzle-kit generate

# Appliquer les migrations
npx drizzle-kit migrate

# Pousser le schéma directement (développement uniquement, pas de fichier de migration)
npx drizzle-kit push

Exemple de Schéma

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)

Workflow (kysely-ctl)

# Initialiser le fichier de configuration (kysely.config.ts)
kysely init

# Créer un nouveau fichier de migration
kysely migrate make add_user_avatar

# Appliquer toutes les migrations en attente
kysely migrate latest

# Revenir à la migration précédente
kysely migrate down

# Afficher l'état des migrations
kysely migrate list

Fichier de Migration

// migrations/2024_01_15_001_create_user_profile.ts
import { type Kysely, sql } from 'kysely'

// IMPORTANT : Utilisez toujours Kysely<any>, pas votre interface DB typée.
// Les migrations sont figées dans le temps et ne doivent pas dépendre des types de schéma actuels.
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()
}

Migrateur Programmateur

import { Migrator, FileMigrationProvider } from 'kysely'
import { promises as fs } from 'fs'
import * as path from 'path'
// ESM uniquement — CJS peut utiliser __dirname directement
import { fileURLToPath } from 'url'
const migrationFolder = path.join(
  path.dirname(fileURLToPath(import.meta.url)),
  './migrations',
)

// `db` est votre instance de base de données Kysely<any>
const migrator = new Migrator({
  db,
  provider: new FileMigrationProvider({
    fs,
    path,
    migrationFolder,
  }),
  // ATTENTION : Activer uniquement en développement. Désactive la validation
  // de l'ordre basé sur le timestamp, ce qui peut provoquer une dérive de schéma entre environnements.
  // allowUnorderedMigrations: true,
})

const { error, results } = await migrator.migrateToLatest()

results?.forEach((it) => {
  if (it.status === 'Success') {
    console.log(`migration "${it.migrationName}" exécutée avec succès`)
  } else if (it.status === 'Error') {
    console.error(`échec de l'exécution de la migration "${it.migrationName}"`)
  }
})

if (error) {
  console.error('échec de la migration', error)
  process.exit(1)
}

Django (Python)

Workflow

# Générer la migration à partir des modifications de modèle
python manage.py makemigrations

# Appliquer les migrations
python manage.py migrate

# Afficher l'état des migrations
python manage.py showmigrations

# Générer une migration vide pour du SQL personnalisé
python manage.py makemigrations --empty app_name -n description

Migration de Données

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  # Migration de données, pas de rollback nécessaire

class Migration(migrations.Migration):
    dependencies = [("accounts", "0015_add_display_name")]

    operations = [
        migrations.RunPython(backfill_display_names, reverse_backfill),
    ]

SeparateDatabaseAndState

Supprimer une colonne du modèle Django sans la supprimer immédiatement de la base de données :

class Migration(migrations.Migration):
    operations = [
        migrations.SeparateDatabaseAndState(
            state_operations=[
                migrations.RemoveField(model_name="user", name="legacy_field"),
            ],
            database_operations=[],  # Ne pas toucher à la base de données encore
        ),
    ]

golang-migrate (Go)

Workflow

# Créer une paire de migrations
migrate create -ext sql -dir migrations -seq add_user_avatar

# Appliquer toutes les migrations en attente
migrate -path migrations -database "$DATABASE_URL" up

# Revenir à la migration précédente
migrate -path migrations -database "$DATABASE_URL" down 1

# Forcer la version (corriger un état sale)
migrate -path migrations -database "$DATABASE_URL" force VERSION

Fichiers de Migration

-- 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;

Stratégie de Migration Zéro Interruption

Pour les changements critiques en production, suivre le modèle expand-contract :

Phase 1 : EXPANSION
  - Ajouter une nouvelle colonne/table (nullable ou avec valeur par défaut)
  - Déployer : l'application écrit à la fois dans l'ANCIEN et le NOUVEAU
  - Backfill des données existantes

Phase 2 : MIGRATION
  - Déployer : l'application lit à partir du NOUVEAU, écrit dans les DEUX
  - Vérifier la cohérence des données

Phase 3 : CONTRACTION
  - Déployer : l'application utilise uniquement le NOUVEAU
  - Supprimer l'ancienne colonne/table dans une migration séparée

Exemple de Calendrier

Jour 1 : Migration ajoute la colonne new_status (nullable)
Jour 1 : Déployer l'application v2 — écrit dans status et new_status
Jour 2 : Exécuter la migration de backfill pour les lignes existantes
Jour 3 : Déployer l'application v3 — lit uniquement depuis new_status
Jour 7 : Migration supprime l'ancienne colonne status

Anti-Patterns

Anti-PatternPourquoi Ça ÉchoueMeilleure Approche
SQL manuel en productionPas de piste d'audit, non reproductibleUtiliser toujours des fichiers de migration
Modifier une migration déployéeProvoque une dérive entre environnementsCréer une nouvelle migration à la place
NOT NULL sans valeur par défautVerrouille la table, réécrit toutes les lignesAjouter nullable, backfill, puis ajouter la contrainte
Index en ligne sur une grande tableBloque les écritures pendant la constructionCREATE INDEX CONCURRENTLY
Schéma + données dans une même migrationDifficile à rollback, transactions longuesMigrations séparées
Supprimer une colonne avant de supprimer le codeErreurs d'application sur colonne manquanteSupprimer le code d'abord, supprimer la colonne au prochain déploiement

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/claude-api

Anthropic Claude API patterns for Python and TypeScript. Covers Messages API, streaming, tool use, vision, extended thinking, batches, prompt caching, and Claude Agent SDK. Use when building applications with the Claude API or Anthropic SDKs.

affaan-m/everything-claude-code

End-to-end marketing campaign planning and execution. Covers audience research, positioning, campaign angle definition, landing page copy, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use as the orchestration layer for multi-channel product launches. Use when planning or executing a multi-channel product launch, or producing landing page, email, social, or ad copy.

affaan-m/everything-claude-code

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/everything-claude-code-conventions

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use when the user asks to build web components, pages, or applications and the visual direction matters as much as the code quality.

affaan-m/gget

gget CLI and Python workflow for quick genomic database queries, sequence lookup, BLAST-style searches, enrichment checks, and reproducible bioinformatics evidence logs.

affaan-m/literature-review

Systematic literature-review workflow for academic, biomedical, technical, and scientific topics, including search planning, source screening, synthesis, citation checks, and evidence logging.

affaan-m/motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

affaan-m/project-guidelines-example

Example project-specific skill template based on a real production application.

affaan-m/pubmed-database

Direct PubMed and NCBI E-utilities search workflows for biomedical literature, MeSH queries, PMID lookup, citation retrieval, and API-backed literature monitoring.

affaan-m/scholar-evaluation

Structured scholarly-work evaluation for papers, proposals, literature reviews, methods sections, evidence quality, citation support, and research-writing feedback.

affaan-m/uspto-database

USPTO patent and trademark data workflow for official record lookup, PatentSearch queries, TSDR checks, assignment data, and reproducible IP research logs.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

Skills associés