Retour au blog
PrismaPostgresDevOpsDatabase

Migrer une base Postgres sans downtime avec Prisma

Renommer une colonne sur 50 millions de lignes sans casser la prod : la recette en 4 étapes.

Publié le 2 avril 20265 min de lecture

Le problème

Tu veux renommer user.email_addr en user.email. Prisma génère une migration ALTER TABLE ... RENAME COLUMN. Sur une grosse table, ça lock pendant la migration — l'API tombe.

La recette "expand & contract"

Étape 1 — Expand (ajouter)

Ajoute la nouvelle colonne nullable, en parallèle de l'ancienne :

model User {
  email_addr String   // ancien
  email      String?  // nouveau, nullable
}

Migration rapide (juste un ADD COLUMN non-bloquant).

Étape 2 — Backfill (copier)

Un script qui copie en chunks :

let cursor = 0;
while (true) {
  const batch = await prisma.user.findMany({
    where: { email: null, id: { gt: cursor } },
    take: 1000,
    orderBy: { id: "asc" },
  });
  if (batch.length === 0) break;
  await prisma.$transaction(
    batch.map((u) =>
      prisma.user.update({
        where: { id: u.id },
        data: { email: u.email_addr },
      })
    )
  );
  cursor = batch[batch.length - 1].id;
}

Étape 3 — Switch (déployer le code qui lit/écrit email)

Le code lit email mais continue à écrire les deux.

Étape 4 — Contract (supprimer)

Une fois 100 % des requêtes basculées, drop email_addr.

Bilan

4 déploiements au lieu d'un, mais 0 downtime. Sur une vraie prod, ça ne se négocie pas.