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

# Migrations van packages publiceren en bijwerken

> Aan de hand van de implementatie in Laravel 13: het verschil tussen publishesMigrations en loadMigrationsFrom, het aanpassen van timestamps bij publicatie, de risico's van opnieuw publiceren en hoe je schemawijzigingen bij bestaande gebruikers krijgt.

Wie een package met een database langdurig onderhoudt, heeft niet alleen een procedure nodig voor de eerste installatie, maar ook een manier om wijzigingen bij gebruikers te krijgen bij wie de tabellen al bestaan. Ontwerp het publiceren, het uitvoeren en de uitvoeringsgeschiedenis van migrations als afzonderlijke processen.

Deze pagina bouwt voort op [Laravel-packages ontwikkelen](/nl/advanced/package-development) en analyseert `ServiceProvider`, `VendorPublishCommand` en `Migrator` in Laravel 13. Voor de implementatie van het framework is `v13.34.0` als referentie gebruikt.

## Kopiëren en overdragen, of laden vanuit het package?

| Methode | Wat de provider doet | Wat de gebruiker doet | Waar de bestanden worden beheerd |
| - | - | - | - |
| Publiceren | `publishesMigrations()` | `migrate` na `vendor:publish` | `database/migrations` van de applicatie |
| Direct laden | `loadMigrationsFrom()` | `migrate` | In het geïnstalleerde package |

`publishesMigrations()` registreert alleen de bron en de bestemming als te publiceren items. Het booten van de provider kopieert geen bestanden en voert geen SQL uit.

`loadMigrationsFrom()` registreert daarentegen een zoekpad bij de Migrator. Een gewone `migrate` neemt dan ook de bestanden in dat pad mee, maar alleen het booten van de provider voert ze niet uit.

```mermaid theme={null}
flowchart TD
    A["Service provider van het package"] --> B["publishesMigrations()<br>Bron en bestemming registreren"]
    B --> C["vendor:publish<br>Naar de applicatie kopiëren"]
    C --> E["migrate<br>Niet-uitgevoerde bestanden uitvoeren"]
    A --> D["loadMigrationsFrom()<br>Toevoegen aan zoekpad van Migrator"]
    D --> E
    E --> F["Namen van uitgevoerde bestanden<br>vastleggen in de migrations-tabel"]
```

Als gebruikers vóór het uitvoeren tabelnamen of kolommen moeten kunnen aanpassen, ligt de publicatiemethode voor de hand. Beheert het package het schema zelf en verwacht je niet dat gebruikers de bestanden bewerken, dan kun je ook de methode met direct laden overwegen. De twee providervoorbeelden hieronder zijn alternatieven voor elkaar.

<Warning>
  Vermijd een ontwerp waarin dezelfde migrations zowel worden gepubliceerd als direct geladen. Als de timestamp bij het publiceren verandert, worden bron en bestemming als afzonderlijke items in de uitvoeringsgeschiedenis behandeld, waardoor dezelfde tabel mogelijk twee keer wordt aangemaakt.
</Warning>

## De publicatiemethode implementeren

Geef een package-specifieke tag op, zodat gebruikers deze resources los van andere resources kunnen publiceren.

```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');
    }
}
```

Bij de eerste installatie kopieer je de bestanden door de provider en de tag op te geven, controleer je de inhoud en voer je ze daarna uit. Geef je beide op, dan kiest Laravel de te publiceren items met die tag die bij die provider horen.

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

### Het aanpassen van timestamps hangt af van een instelling

De officiële documentatie beschrijft dat de timestamps van migrations bij het publiceren worden bijgewerkt naar de huidige datum en tijd. In de implementatie van `ServiceProvider::publishesMigrations()` wordt de bron echter alleen aan de items voor timestampaanpassing toegevoegd als `database.migrations.update_date_on_publish` is ingeschakeld. De fallback bij het ophalen van deze instelling is `false`.

De standaardapplicatie van Laravel 13 bevat in `config/database.php` de volgende instelling. Controleer bij applicaties die een oudere structuur hebben overgenomen ook of deze instelling bestaat.

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

Daarnaast herschrijft `VendorPublishCommand` de datum en tijd als het bestand overeenkomt met het werkelijke pad van een geregistreerde bron en de bestemmingsnaam het formaat `YYYY_MM_DD_HHMMSS_` bevat. Uitgaande van het starttijdstip van het commando wordt per bestand één seconde opgeteld. Bevat de naam dit formaat niet, dan voegt deze stap geen datum en tijd toe.

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

Voorbeeld na publicatie:
2026_10_02_120001_create_courier_deliveries_table.php
```

De datum en tijd na publicatie hierboven dienen alleen ter illustratie. De werkelijke bestandsnaam hangt af van het moment waarop je publiceert.

<Info>
  Het bijwerken van timestamps hangt af van zowel de registratie in het package als de instellingen van de applicatie die het gebruikt. Wijzig deze instelling niet zomaar vanuit de provider van het package, maar beschrijf de voorwaarde in de installatie-instructies. Gebruik je een configuratiecache, dan moet die na het wijzigen van de instelling ook opnieuw worden opgebouwd.
</Info>

## Opnieuw publiceren is niet "alleen niet-uitgevoerde bestanden toevoegen"

`vendor:publish` controleert de uitvoeringsgeschiedenis in de database niet. Bovendien controleert de kopieerstap in `v13.34.0` op bestaande bestanden aan de hand van de bestemming **vóór de timestampaanpassing**. Ook bij het publiceren van een map wordt eerst gecontroleerd of hetzelfde relatieve pad als de bron al op de bestemming bestaat, en pas daarna worden datum en tijd herschreven.

Als de datum en tijd bij de eerste publicatie zijn veranderd en er in de applicatie geen bestand met dezelfde naam als de bron staat, kan het opnieuw publiceren van dezelfde tag dus een bestand met een andere datum en tijd toevoegen. Ga er niet van uit dat je duplicaten altijd voorkomt door `--force` weg te laten.

| Voorwaarde | Waar je op moet letten bij opnieuw publiceren |
| - | - |
| Timestampaanpassing ingeschakeld en de bestemming vóór aanpassing bestaat niet | Er kan een kopie met een andere datum en tijd worden toegevoegd |
| Timestampaanpassing uitgeschakeld en de bestemming heeft dezelfde naam | Het bestaande bestand wordt normaal gesproken overgeslagen |
| `--force` opgegeven | Als aan de kopieervoorwaarden is voldaan en timestampaanpassing is ingeschakeld, kan het bestand een andere naam krijgen |
| `--existing` opgegeven | Omdat het bestaan van de bestemming vóór aanpassing wordt gecontroleerd, wordt een bestand niet per se meegenomen als alleen het bestand met aangepaste datum bestaat |

### Of iets is uitgevoerd, wordt bepaald aan de hand van de bestandsnaam

`Migrator::getMigrationName()` geeft de basisnaam van het bestand zonder `.php` terug. Om te bepalen of een migration nog niet is uitgevoerd, wordt deze naam vergeleken met de uitvoeringsgeschiedenis. Of de PHP-inhoud of de tabelnaam hetzelfde is, speelt bij deze beoordeling geen rol.

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

Dit zijn twee verschillende migrationnamen. Ook als de eerste al is uitgevoerd, geldt de tweede op basis van die geschiedenis niet als uitgevoerd.

<Warning>
  Voer bij elke package-update niet zonder meer het publicatiecommando voor de eerste installatie opnieuw uit, en maak `--force` geen standaardstap. Dat kan niet alleen wijzigingen in gepubliceerde bestanden overschrijven, maar door de timestampaanpassing ook dubbele bewerkingen toevoegen.
</Warning>

## De methode met direct laden implementeren

Als je de migrations in het package direct wilt laten uitvoeren, registreer je een zoekpad. Bij deze methode voeg je geen stap toe om dezelfde bestanden te publiceren.

```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()` roept `path()` aan zodra de Migrator wordt geresolved. `Migrator::path()` verwijdert dubbele zoekpaden, en `getMigrationFiles()` gebruikt de migrationnaam als sleutel voor de gevonden bestanden en sorteert ze op die naam.

Wanneer een gebruiker het package bijwerkt, worden nieuwe bestanden bij de volgende `migrate` meegenomen. Wijzig de namen van bestaande bestanden niet en voeg voor nieuwe schemawijzigingen nieuwe bestanden toe. Neem ook de naam van de functionaliteit op, zoals in `create_courier_deliveries_table`, om conflicten met andere packages te voorkomen. Bestanden met dezelfde naam krijgen dezelfde sleutel; ze worden niet allebei onafhankelijk uitgevoerd.

<Warning>
  Overstappen van de publicatiemethode naar direct laden is niet zomaar een kwestie van de provider herschrijven. Als de uitvoeringsgeschiedenis van gebruikers is vastgelegd onder de namen van het moment van publicatie, komen die niet overeen met de oorspronkelijke namen in het package. Je hebt een migratieplan nodig dat rekening houdt met de geschiedenis, de gepubliceerde bestanden en rollbacks van bestaande gebruikers.
</Warning>

## Schemawijzigingen bij bestaande gebruikers krijgen

Wil je bijvoorbeeld een trackingnummer aan de bezorgtabel toevoegen, bewerk dan niet de al gepubliceerde `create_courier_deliveries_table`, maar voeg een nieuw bestand voor de wijziging toe. Als je een bestaande aanmaak-migration bewerkt, wordt die wijziging bij gebruikers die hem al hebben uitgevoerd niet doorgevoerd.

```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');
        });
    }
};
```

Omdat dit voorbeeld een kolom toevoegt aan een tabel met bestaande rijen, is de kolom hier nullable. Moet de kolom verplicht worden of moeten gegevens worden aangevuld, ontwerp die stappen en de uitvoeringsvolgorde dan apart.

Bij de publicatiemethode bied je een updateprocedure die de gepubliceerde bestanden van de gebruiker vergelijkt en **alleen de nu toegevoegde bestanden** levert. Je kunt ook een aparte publicatietag voor nieuwe bestanden aanmaken, maar als timestampaanpassing is ingeschakeld, geldt voor het herhaald uitvoeren van die tag dezelfde waarschuwing. Maak van de updateprocedure niet simpelweg het opnieuw uitvoeren van de tag voor de eerste installatie.

Bij direct laden detecteert de bijgewerkte code de nieuwe bestanden. Bij beide methoden verandert de database niet alleen doordat de bestanden bestaan, dus vermeld in de release notes dat migrations moeten worden uitgevoerd.

## Wat je vóór een release controleert

Controleer naast de databasetests van het package ook de publicatie- en updateprocedure in een applicatie die het package gebruikt. Alleen migrations direct laden in tests betekent niet dat je de publicatiemethode, waarbij bestandsnamen veranderen, hebt gevalideerd.

* Een eerste installatie op een lege database maakt de benodigde tabellen aan.
* Bij een update vanaf de database en uitvoeringsgeschiedenis van een oudere release worden alleen de nieuwe wijzigingen toegepast.
* Je hebt de bestandslijst bekeken na het herhaald uitvoeren van hetzelfde publicatiecommando, en de updateprocedure veroorzaakt geen duplicaten.
* De procedure houdt rekening met in- of uitgeschakelde timestampaanpassing en met bewerkte gepubliceerde bestanden.
* Je hebt de rollback van nieuwe migrations en de uitvoeringsvolgorde ten opzichte van de andere migrations van de applicatie gecontroleerd.

## Gerelateerde pagina's

<Columns cols={2}>
  <Card title="Migrations" icon="database" href="/nl/migrations">
    Bekijk de basis van schemadefinities, uitvoeringsgeschiedenis en rollbacks.
  </Card>

  <Card title="Packages testen" icon="flask" href="/nl/advanced/package-testing">
    Test de service provider en de database van je package.
  </Card>

  <Card title="Packageconfiguratie samenvoegen en cachen" icon="sliders" href="/nl/advanced/package-config-merging">
    Bekijk updateprocedures die rekening houden met gebruikersinstellingen en de configuratiecache.
  </Card>

  <Card title="Versiecompatibiliteit beheren" icon="code-branch" href="/nl/advanced/package-versioning">
    Koppel updateprocedures en compatibiliteitswijzigingen aan je releasebeleid.
  </Card>
</Columns>

## Geraadpleegde primaire bronnen

* [Officiële Laravel-documentatie: migrations van packages](https://github.com/laravel/docs/blob/156fc7fde114548640e13c39aa79b991291c3f91/packages.md#migrations)
* [ServiceProvider: registratie van te publiceren items en zoekpaden](https://github.com/laravel/framework/blob/v13.34.0/src/Illuminate/Support/ServiceProvider.php)
* [VendorPublishCommand: kopiëren en timestampaanpassing](https://github.com/laravel/framework/blob/v13.34.0/src/Illuminate/Foundation/Console/VendorPublishCommand.php)
* [Migrator: detectie van bestanden en bepalen wat nog niet is uitgevoerd](https://github.com/laravel/framework/blob/v13.34.0/src/Illuminate/Database/Migrations/Migrator.php)
* [Standaardapplicatie van Laravel 13: databaseconfiguratie](https://github.com/laravel/laravel/blob/06d016a364a37430eec9cbc52209adce3d7667ce/config/database.php)


## Related topics

- [Laravel-packages ontwikkelen](/nl/advanced/package-development.md)
- [Laravel Boost](/nl/boost.md)
- [Upgraden van Laravel 10 naar 11](/nl/blog/upgrade-10-to-11.md)
- [Laravel AI SDK](/nl/ai-sdk.md)
- [Packageconfiguratie samenvoegen en cachen](/nl/advanced/package-config-merging.md)


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