> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Publier et mettre à jour les migrations d'un package

> À partir de l'implémentation de Laravel 13, découvrez la différence entre publishesMigrations et loadMigrationsFrom, la modification des horodatages lors de la publication, les risques d'une republication et la manière de livrer des changements de schéma aux utilisateurs existants.

Pour maintenir dans la durée un package qui utilise la base de données, il ne suffit pas de gérer la première installation : il faut aussi une procédure pour livrer les changements aux utilisateurs dont les tables existent déjà. Concevez la publication des migrations, leur exécution et leur historique d'exécution comme des traitements distincts.

Cette page part des [bases du développement de packages](/fr/advanced/package-development) et analyse `ServiceProvider`, `VendorPublishCommand` et `Migrator` de Laravel 13. L'implémentation du framework citée correspond à `v13.34.0`.

## Copier les fichiers ou les charger depuis le package ?

| Méthode | Traitement dans le provider | Action de l'utilisateur | Emplacement des fichiers |
| - | - | - | - |
| Publication | `publishesMigrations()` | `migrate` après `vendor:publish` | `database/migrations` de l'application |
| Chargement direct | `loadMigrationsFrom()` | `migrate` | Dans le package installé |

`publishesMigrations()` se contente d'enregistrer la source et la destination comme éléments publiables. Le démarrage du provider ne copie aucun fichier et n'exécute aucun SQL.

À l'inverse, `loadMigrationsFrom()` enregistre un chemin de recherche auprès du Migrator. Les fichiers de ce chemin sont alors pris en compte par un `migrate` ordinaire, mais le simple démarrage du provider ne les exécute pas.

```mermaid theme={null}
flowchart TD
    A["Service provider du package"] --> B["publishesMigrations()<br>Enregistre la source et la destination"]
    B --> C["vendor:publish<br>Copie dans l'application"]
    C --> E["migrate<br>Exécute les fichiers non exécutés"]
    A --> D["loadMigrationsFrom()<br>Ajoute au chemin de recherche du Migrator"]
    D --> E
    E --> F["Enregistre les noms des fichiers exécutés<br>dans la table migrations"]
```

Si l'utilisateur doit pouvoir ajuster les noms de tables ou les colonnes avant l'exécution, la publication est l'approche à envisager. Si le package gère lui-même le schéma et ne suppose pas que l'utilisateur modifie les fichiers, le chargement direct est aussi une option. Les deux exemples de provider ci-dessous sont des alternatives.

<Warning>
  Évitez de publier une migration tout en la chargeant aussi directement. Si l'horodatage change lors de la publication, la source et la copie sont traitées comme deux entrées distinctes de l'historique d'exécution, et la même création de table risque d'être exécutée deux fois.
</Warning>

## Implémenter la publication

Attribuez un tag propre au package pour que l'utilisateur puisse publier ces fichiers indépendamment des autres ressources.

```php theme={null}
<?php

namespace Acme\Courier;

use Illuminate\Support\ServiceProvider;

class CourierServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        $this->publishesMigrations([
            __DIR__.'/../database/migrations' => database_path('migrations'),
        ], 'courier-migrations');
    }
}
```

Lors de la première installation, copiez les fichiers en indiquant le provider et le tag, vérifiez leur contenu, puis exécutez-les. Lorsque les deux sont précisés, Laravel sélectionne les éléments publiables de ce tag qui appartiennent à ce provider.

```bash theme={null}
php artisan vendor:publish --provider="Acme\Courier\CourierServiceProvider" --tag=courier-migrations
php artisan migrate:status
php artisan migrate
```

### La modification de l'horodatage dépend de la configuration

La documentation officielle indique que l'horodatage des migrations est remplacé par la date et l'heure actuelles lors de la publication. Toutefois, l'implémentation de `ServiceProvider::publishesMigrations()` n'ajoute la source aux éléments dont l'horodatage doit être mis à jour que si `database.migrations.update_date_on_publish` est activé. La valeur de repli lors de la lecture de ce paramètre est `false`.

Le fichier `config/database.php` de l'application standard de Laravel 13 contient le paramètre suivant. Pour une application qui a hérité d'une ancienne structure, vérifiez aussi que ce paramètre existe.

```php theme={null}
'migrations' => [
    'table' => 'migrations',
    'update_date_on_publish' => true,
],
```

De plus, `VendorPublishCommand` réécrit la date lorsque le chemin réel correspond à une source enregistrée et que le nom de destination contient le format `YYYY_MM_DD_HHMMSS_`. En partant de l'heure de lancement de la commande, il ajoute une seconde pour chaque fichier concerné. Si le nom ne contient pas ce format, ce traitement n'ajoute aucune date.

```text theme={null}
Source :
2026_09_01_000000_create_courier_deliveries_table.php

Exemple après publication :
2026_10_02_120001_create_courier_deliveries_table.php
```

La date après publication ci-dessus est donnée à titre d'illustration. Le nom de fichier réel dépend du moment de la publication.

<Info>
  La mise à jour de l'horodatage dépend à la fois de l'enregistrement effectué par le package et de la configuration de l'application qui l'utilise. Ne modifiez pas ce paramètre de manière uniforme depuis le provider du package : documentez plutôt ce prérequis dans la procédure d'installation. Si le cache de configuration est utilisé, il faut aussi le reconstruire après avoir modifié la configuration.
</Info>

## Republier ne signifie pas « ajouter uniquement ce qui n'a pas été exécuté »

`vendor:publish` ne consulte pas l'historique d'exécution de la base de données. En outre, dans le traitement de copie de `v13.34.0`, la vérification de l'existence d'un fichier porte sur la destination **avant la modification de l'horodatage**. Même pour la publication d'un répertoire, la commande vérifie d'abord si le même chemin relatif que la source existe dans la destination, puis réécrit la date.

Par conséquent, si la date a changé lors de la première publication et qu'aucun fichier portant le même nom que la source n'existe côté application, publier à nouveau le même tag peut ajouter un fichier avec une autre date. Ne partez pas du principe que l'absence de `--force` empêche toujours les doublons.

| Condition | Point d'attention lors d'une republication |
| - | - |
| Mise à jour de la date activée et destination d'origine inexistante | Une copie avec une autre date peut être ajoutée |
| Mise à jour de la date désactivée et destination portant le même nom | Le fichier existant est normalement ignoré |
| `--force` spécifié | Si les conditions de copie sont remplies et que la mise à jour de la date est activée, le nom peut être différent |
| `--existing` spécifié | L'existence de la destination d'origine étant vérifiée, la seule présence d'un fichier dont la date a changé ne garantit pas qu'il soit concerné |

### L'état d'exécution est déterminé par le nom de fichier

`Migrator::getMigrationName()` renvoie le nom de base du fichier sans `.php`. Pour déterminer si une migration n'a pas encore été exécutée, ce nom est comparé à l'historique d'exécution. La décision ne repose pas sur le contenu PHP ni sur l'identité des noms de tables.

```text theme={null}
2026_10_02_120001_create_courier_deliveries_table
2026_10_03_090001_create_courier_deliveries_table
```

Ce sont deux noms de migration différents. Même si la première a été exécutée, cet historique seul ne fait pas considérer la seconde comme exécutée.

<Warning>
  Ne relancez pas systématiquement la commande de publication destinée à la première installation à chaque mise à jour du package, et ne faites pas de `--force` une étape standard. Non seulement les modifications des fichiers publiés seraient écrasées, mais le changement de date pourrait aussi ajouter des traitements en double.
</Warning>

## Implémenter le chargement direct

Si vous souhaitez que les migrations du package soient exécutées telles quelles, enregistrez un chemin de recherche. Avec cette approche, n'ajoutez pas de traitement publiant les mêmes fichiers.

```php theme={null}
<?php

namespace Acme\Courier;

use Illuminate\Support\ServiceProvider;

class CourierServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        $this->loadMigrationsFrom(__DIR__.'/../database/migrations');
    }
}
```

`loadMigrationsFrom()` appelle `path()` lorsque le Migrator est résolu. `Migrator::path()` élimine les chemins de recherche en double, et `getMigrationFiles()` indexe les fichiers trouvés par nom de migration puis les trie selon ce nom.

Lorsque l'utilisateur met à jour le package, les nouveaux fichiers sont pris en compte par le `migrate` suivant. Ne renommez pas les fichiers existants et ajoutez un nouveau fichier pour chaque nouveau changement de schéma. Pour éviter les collisions avec d'autres packages, incluez aussi le nom de la fonctionnalité, comme dans `create_courier_deliveries_table`. Des fichiers de même nom ont la même clé : ils ne sont pas exécutés indépendamment l'un de l'autre.

<Warning>
  Passer de la publication au chargement direct ne se résume pas à réécrire le provider. Si l'historique d'exécution de l'utilisateur a été enregistré avec les noms attribués lors de la publication, ceux-ci ne correspondent pas aux noms d'origine côté package. Il faut une procédure de migration couvrant l'historique des utilisateurs existants, les fichiers publiés et les rollbacks.
</Warning>

## Livrer des changements de schéma aux utilisateurs existants

Par exemple, pour ajouter un numéro de suivi à la table des livraisons, n'éditez pas le fichier `create_courier_deliveries_table` déjà publié : ajoutez un nouveau fichier dédié à ce changement. Modifier une migration de création existante n'appliquera pas ce changement chez les utilisateurs qui l'ont déjà exécutée.

```php database/migrations/2026_10_02_000000_add_tracking_code_to_courier_deliveries_table.php theme={null}
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up(): void
    {
        Schema::table('courier_deliveries', function (Blueprint $table) {
            $table->string('tracking_code')->nullable();
        });
    }

    public function down(): void
    {
        Schema::table('courier_deliveries', function (Blueprint $table) {
            $table->dropColumn('tracking_code');
        });
    }
};
```

Comme il s'agit d'un ajout à une table qui contient déjà des lignes, la colonne est ici nullable. Si vous devez la rendre obligatoire ou remplir les données existantes, concevez séparément cette procédure et son ordre d'exécution.

Avec la publication, prévoyez une procédure de mise à jour qui compare les fichiers déjà publiés chez l'utilisateur et ne livre **que les fichiers ajoutés dans cette version**. Vous pouvez créer un tag de publication réservé aux nouveaux fichiers, mais si la mise à jour de la date est activée, la même prudence s'applique à l'exécution répétée de ce tag. Ne réduisez pas la procédure de mise à jour à la simple réexécution du tag de première installation.

Avec le chargement direct, le code mis à jour détecte les nouveaux fichiers. Dans les deux cas, la simple présence d'un fichier ne modifie pas la base de données : indiquez donc clairement dans les notes de version qu'il faut exécuter les migrations.

## Vérifications avant la publication d'une version

En plus des tests de base de données du package, vérifiez les procédures de publication et de mise à jour dans une application qui l'utilise. Charger directement les migrations dans les tests ne suffit pas à valider l'approche par publication, dans laquelle les noms de fichiers changent.

* Une première installation sur une base vide crée les tables nécessaires.
* Une mise à jour depuis la base et l'historique d'exécution d'une version précédente n'applique que les nouveaux changements.
* La liste des fichiers après plusieurs exécutions de la même commande de publication a été vérifiée, et la procédure de mise à jour ne crée pas de doublons.
* La procédure tient compte de l'activation ou non de la mise à jour de la date, ainsi que des modifications apportées aux fichiers publiés.
* Le rollback des nouvelles migrations et leur ordre d'exécution par rapport aux autres migrations de l'application ont été vérifiés.

## Pages associées

<Columns cols={2}>
  <Card title="Migrations" icon="database" href="/fr/migrations">
    Les bases de la définition du schéma, de l'historique d'exécution et des rollbacks.
  </Card>

  <Card title="Tester un package" icon="flask" href="/fr/advanced/package-testing">
    Tester le service provider et la base de données d'un package.
  </Card>

  <Card title="Fusion et mise en cache de la configuration d'un package" icon="sliders" href="/fr/advanced/package-config-merging">
    Une procédure de mise à jour qui tient compte de la configuration de l'utilisateur et du cache de configuration.
  </Card>

  <Card title="Gestion de la compatibilité des versions" icon="code-branch" href="/fr/advanced/package-versioning">
    Relier les procédures de mise à jour et les changements de compatibilité à votre politique de publication.
  </Card>
</Columns>

## Sources primaires consultées

* [Documentation officielle de Laravel : migrations des packages](https://github.com/laravel/docs/blob/156fc7fde114548640e13c39aa79b991291c3f91/packages.md#migrations)
* [ServiceProvider : enregistrement des éléments publiables et des chemins de recherche](https://github.com/laravel/framework/blob/v13.34.0/src/Illuminate/Support/ServiceProvider.php)
* [VendorPublishCommand : copie et modification de l'horodatage](https://github.com/laravel/framework/blob/v13.34.0/src/Illuminate/Foundation/Console/VendorPublishCommand.php)
* [Migrator : détection des fichiers et identification des migrations non exécutées](https://github.com/laravel/framework/blob/v13.34.0/src/Illuminate/Database/Migrations/Migrator.php)
* [Application standard de Laravel 13 : configuration de la base de données](https://github.com/laravel/laravel/blob/06d016a364a37430eec9cbc52209adce3d7667ce/config/database.php)


## Related topics

- [Développement de packages Laravel](/fr/advanced/package-development.md)
- [Sujets avancés](/fr/advanced/index.md)
- [Gestion de la compatibilité de versions de package](/fr/advanced/package-versioning.md)
- [Feed Generator](/fr/packages/laravel-bluesky/feed-generator.md)
- [Mise à niveau de Laravel 10 à 11](/fr/blog/upgrade-10-to-11.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.