Skip to main content
DBを使うパッケージを継続して保守するには、初回インストールだけでなく、すでにテーブルが存在する利用者へ変更を届ける手順が必要です。マイグレーションの公開、実行、実行履歴は別の処理として設計してください。 このページではパッケージ開発の基礎を前提に、Laravel 13の ServiceProvider、VendorPublishCommand、Migrator を読み解きます。フレームワークの実装は v13.34.0 を参照しています。

コピーして渡すか、パッケージから読み込むか

publishesMigrations() は、コピー元とコピー先を公開対象として登録するだけです。プロバイダーを起動しても、ファイルのコピーやSQLの実行は行いません。 一方、loadMigrationsFrom() はMigratorに検索パスを登録します。通常の migrate でそのパスのファイルも対象になりますが、プロバイダーの起動だけでは実行されません。 利用者が実行前にテーブル名やカラムを調整する設計なら、公開方式が候補になります。パッケージがスキーマを管理し、利用者によるファイル編集を前提としないなら、直接読み込み方式も検討できます。以下の2つのプロバイダー例は代替案です。
同じマイグレーションを公開しつつ直接読み込ませる設計は避けてください。公開時にタイムスタンプが変わると、コピー元とコピー先は別の実行履歴として扱われ、同じテーブル作成処理が二重に実行されるおそれがあります。

公開方式を実装する

パッケージ固有のタグを付け、利用者が他のリソースと区別して公開できるようにします。
初回インストールでは、対象プロバイダーとタグを指定してコピーし、内容を確認してから実行します。両方を指定した場合、Laravelはそのプロバイダーに属する、そのタグの公開対象を選びます。

タイムスタンプの変更には設定が関係する

公式ドキュメントは、公開時にマイグレーションのタイムスタンプを現在日時へ更新する動作を説明しています。ただし、ServiceProvider::publishesMigrations() の実装では、database.migrations.update_date_on_publish が有効な場合にだけ、コピー元をタイムスタンプ更新対象へ追加します。この設定を取得するときのフォールバックは false です。 Laravel 13の標準アプリケーションの config/database.php には、次の設定があります。旧構成を引き継いだアプリケーションでは、設定が存在するかも確認してください。
さらに VendorPublishCommand は、登録されたコピー元の実パスと一致し、コピー先の名前に YYYY_MM_DD_HHMMSS_ 形式がある場合に日時を書き換えます。コマンド開始時刻を基準に、対象ファイルごとに1秒加算します。名前にこの形式がなければ、その処理では日時を付け足しません。
上の公開後の日時は説明用です。実際のファイル名は公開した時刻によって変わります。
タイムスタンプ更新は、パッケージの登録と利用アプリケーションの設定の両方に依存します。パッケージのプロバイダーからこの設定を一律に変更せず、インストール手順に前提を記載してください。設定キャッシュを利用している場合は、設定変更後の再構築も必要です。

再公開は「未実行のものだけ追加」ではない

vendor:publish はDBの実行履歴を確認しません。また、v13.34.0 のコピー処理では、既存ファイルの確認をタイムスタンプの変更前のコピー先に対して行います。ディレクトリ公開でも、まずコピー元と同じ相対パスがコピー先にあるかを確認し、その後で日時を書き換えます。 そのため、最初の公開で日時が変わり、コピー元と同じ名前のファイルがアプリケーション側にない場合は、同じタグをもう一度公開すると別の日時のファイルが追加されることがあります。--force を付けなければ常に重複を防げる、とは考えないでください。

実行済みかどうかはファイル名で判断する

Migrator::getMigrationName() は、ファイルのベース名から .php を除いた文字列を返します。未実行の判定では、この名前と実行履歴を比較します。PHPの内容やテーブル名が同じかどうかによる判定ではありません。
この2つは別のマイグレーション名です。前者が実行済みでも、後者はその履歴だけでは実行済みになりません。
パッケージ更新のたびに初回インストール用の公開コマンドを無条件で再実行したり、--force を標準手順にしたりしないでください。公開済みファイルの編集を上書きするだけでなく、日時変更によって重複した処理を追加する可能性があります。

直接読み込み方式を実装する

パッケージ内のマイグレーションをそのまま実行対象にしたい場合は、検索パスを登録します。この方式では、同じファイルを公開する処理は追加しません。
loadMigrationsFrom() はMigratorが解決されたときに path() を呼びます。Migrator::path() は検索パスの重複を除き、getMigrationFiles() は見つけたファイルをマイグレーション名でキー付けして、その名前順に並べます。 利用者がパッケージを更新すると、新しいファイルは次の migrate の対象になります。既存ファイルの名前は変えず、新しいスキーマ変更には新しいファイルを追加します。他のパッケージとの衝突を避けるため、create_courier_deliveries_table のように機能名も含めてください。同名のファイルは同じキーになり、両方が独立して実行されるわけではありません。
公開方式から直接読み込み方式への変更は、単なるプロバイダーの書き換えではありません。利用者の実行履歴が公開時の名前で記録されている場合、パッケージ側の元の名前と一致しません。既存利用者の履歴・公開済みファイル・ロールバックを含む移行手順が必要です。

スキーマ変更を既存利用者へ届ける

たとえば配送テーブルへ追跡番号を追加する場合は、公開済みの create_courier_deliveries_table を編集するのではなく、変更用の新しいファイルを追加します。既存の作成マイグレーションを編集しても、実行済みの利用者にはその変更が実行されません。
database/migrations/2026_10_02_000000_add_tracking_code_to_courier_deliveries_table.php
既存行があるテーブルへ追加する例なので、ここではnullableにしています。必須化やデータの埋め戻しが必要なら、別途その手順と実行順序を設計します。 公開方式では、利用者の公開済みファイルと照合し、今回追加したファイルだけを届ける更新手順を用意します。新規ファイル専用の公開タグを設ける方法もありますが、日時更新が有効ならそのタグの繰り返し実行にも同じ注意が必要です。初回用タグを再実行するだけの更新手順にはしません。 直接読み込み方式では、更新後のコードで新しいファイルを検出できます。どちらの方式でも、ファイルが存在するだけではDBは変わらないため、リリースノートにマイグレーション実行の必要性を明記します。

リリース前に確認すること

パッケージのDBテストに加えて、利用アプリケーションで公開と更新の手順を確認してください。テストでマイグレーションを直接読み込むだけでは、ファイル名が変わる公開方式を検証したことにはなりません。
  • 空のDBに初回インストールし、必要なテーブルを作成できる。
  • 旧リリースのDBと実行履歴から更新し、新しい変更だけが適用される。
  • 同じ公開コマンドを繰り返したときのファイル一覧を確認し、更新手順が重複を生まない。
  • 日時更新の有効・無効と、公開済みファイルの編集を考慮した手順になっている。
  • 新規マイグレーションのロールバックと、アプリケーションの他のマイグレーションとの実行順序を確認する。

関連ページ

マイグレーション

スキーマ定義、実行履歴、ロールバックの基本を確認します。

パッケージのテスト

パッケージのサービスプロバイダーとDBをテストします。

パッケージ設定のマージとキャッシュ

利用者の設定と設定キャッシュを考慮した更新手順を確認します。

バージョン互換性管理

更新手順と互換性の変更をリリース方針に結び付けます。

参照した一次情報

最終更新日 2026年10月2日