Branches et migrations
Cette page dit comment faire évoluer le schéma de votre base sans surprise : appliquer une migration après l'avoir répétée sur la base réelle, et lire chaque nuit l'écart entre le schéma que déclare votre dépôt et la base qui tourne. Elle dit aussi où en sont les branches de base de données : prévues, elles ne sont pas encore disponibles.
Les branches de base de données : pas encore disponibles
La grille prévoit des branches de base, une copie de la base par branche du dépôt (1 en Découverte, 3 en Standard, 25 en Pro, 50 en Souverain). Elles ne sont pas encore servies : aucun écran, aucun outil et aucune opération ne crée ni ne liste une branche.
Ce que cela veut dire aujourd'hui :
- Toutes les classes d'environnement partagent la même base. Une prévisualisation, la préproduction et la production reçoivent la même
DATABASE_URL(voir Base de données). Une migration jouée depuis une prévisualisation touche donc la base de production. - Pour essayer un schéma à part, créez un second projet avec sa propre base (
project_create_with_backend), ou posez vous-mêmeDATABASE_URLsur l'environnement de prévisualisation vers une autre base : votre variable l'emporte sur celle de Bastide.
Attention. Ne lancez pas
prisma migrate deployou un équivalent au démarrage d'une prévisualisation : il modifierait la base de production.
Appliquer une migration de schéma
Une migration passe toujours par deux passes, dans cet ordre :
- La répétition. La migration est jouée sur la base réelle, dans une transaction annulée : même schéma, mêmes lignes, mêmes verrous, et rien ne reste. La plateforme mesure sa durée, les verrous qu'elle prend (au mode le plus fort par relation) et, quand elle est certaine, sa migration inverse.
- L'application. La migration est rejouée et validée. Ce qui est rendu est la mesure de cette seconde passe : la base a pu changer entre les deux.
Ce qui est refusé :
- Un effet destructif : une table supprimée ou vidée, une colonne retirée (
migration_destructive). Ce geste passe par l'éditeur SQL en écriture, qui le fait confirmer et retaper (voir Base de données). - Le contrôle de transaction et l'état de session dans le texte (
BEGIN,COMMIT,SET,COPY, curseurs,set_config) : la migration validerait sinon sa propre répétition. - Plus de 200 instructions : découpez la migration en plusieurs appels.
- Une instruction que la base refuse (
migration_refusee_par_la_base) : rien n'est appliqué ; le détail nomme l'instruction et son état SQL.
La migration inverse n'est rendue que si chaque instruction en a une certaine : créer une table, une vue, un index, une séquence, un schéma, ou ajouter une colonne. Elle détruit ce que la migration a créé, et se joue par database_sql_write. Une migration validée ne se défait pas par action_undo.
Depuis la console
Ouvrez Données, section « Migrations ».
- Collez les instructions de la migration.
- Cliquez sur « Répéter puis annuler » : la page montre les verrous pris, la durée de la répétition et la migration inverse si elle existe.
- Relisez la carte « Avant d'appliquer », puis cliquez sur « Appliquer la migration ».
Seul le rang Mainteneur applique ; chaque application entre au journal d'audit. La page dit « non mesuré » pour ce que la plateforme ne publie pas encore : l'historique des migrations appliquées, les lignes touchées et les requêtes en attente.
Par un agent, la ligne de commande ou l'API
L'outil database_migrate (rang maintainer, portée db:write) prend sql et, pour s'arrêter après la répétition, dryRun: true. Une personne valide l'appel avant qu'il parte ; un compte de service ne l'exécute pas.
{
"projectId": "prj_01JQ8ZK4M7NP2RSTVWXYZ34567",
"sql": "alter table commandes add column livree_le timestamptz;",
"dryRun": true,
"idempotencyKey": "migration-livree-le-a-blanc-2026-09-14"
}
La réponse porte applied, durationMs, locksAcquired et rollbackSql. En ligne de commande : bastide database migrate --project-id <projet> --sql <instructions> --dry-run. En HTTP : POST /v1/projects/{projectId}/database/migrations.
L'écart de schéma
Chaque nuit, la plateforme rejoue les migrations du dossier supabase/migrations/ de votre dépôt, dans l'ordre de leurs noms, sur une base à part qui porte le même socle que la vôtre. Puis elle compare les deux, objet par objet : schémas, extensions, tables, vues, colonnes, contraintes, index, politiques, fonctions. Le SQL de votre dépôt s'y exécute sous un rôle de client, jamais sous l'administrateur.
Chaque écart a une nature et porte les deux définitions :
| Nature | Ce qu'elle dit |
|---|---|
missing_in_database | Déclaré au dépôt, absent de la base. |
missing_in_repository | Présent dans la base, absent du dépôt : souvent une modification faite à la main. |
different | Défini autrement dans la base. |
L'état est conforme, ecart ou non_mesure. Une comparaison qui n'a pas pu se faire (pas de dépôt raccordé, pas de dossier de migrations, une migration qui ne se rejoue pas) est « non mesurée », avec sa raison : une absence d'écart ne se lit jamais comme une base conforme.
Un écart nouveau émet l'événement database.schema.drifted vers les points de réception du projet (voir Webhooks). Le même écart, la nuit suivante, ne réémet pas.
Où le lire
- Console : Données, section « Migrations » (les écarts, avec « Voir les définitions »), et section « Sécurité », sous la posture.
- Agent :
backend_schema_drift_read(rangmaintainer, portéedb:read). - Ligne de commande :
bastide backend schema_drift read --project-id <projet>. - API :
GET /v1/projects/{projectId}/backend/schema-drift.
La réponse porte comparedAt (nul tant qu'aucune comparaison n'a eu lieu), state, commitSha, declaredMigrations, comparedObjects, drifts (cent au plus, truncated au-delà), driftCount et notMeasured.
Erreurs fréquentes
- **
migration_destructive** : votre migration retire une colonne ou une table. Passez pardatabase_sql_write, qui le fait confirmer. - **
migration_refusee_par_la_base** : corrigez l'instruction nommée ; rien n'a été appliqué. - **
state: non_mesure** : liseznotMeasured. Le plus souvent, le dépôt n'a pas de dossiersupabase/migrations/, ou une migration ne se rejoue pas sur une base vide. - **Un écart
missing_in_repositoryaprès un essai dans l'éditeur SQL** : reportez la modification dans une migration du dépôt, ou défaites-la.