4.

Laravel の migrate 実行|rollback・fresh の違いと本番での手順

編集
この記事の要点
  • 実行は php artisan migrate。未実行のマイグレーションだけが順に適用される
  • 実行前に --pretend で発行される SQL を確認できる
  • 戻すのは migrate:rollback直前のバッチ全体が戻る(1 件だけではない)
  • migrate:fresh は全テーブルを削除する。本番で実行してはいけない
  • 本番は非対話なので --force が必要。実行前にバックアップを取る

基本の流れ

php artisan make:migration create_tasks_table    # ファイルを作る
php artisan migrate --pretend                    # SQL を確認する
php artisan migrate                              # 実行する
php artisan migrate:status                       # 状態を確認する
INFO  Running migrations.

2026_09_07_120000_create_tasks_table .................... 24ms DONE

Laravel は migrations テーブルに実行済みのファイル名とバッチ番号を記録します。すでに実行したものは飛ばされるので、何度実行しても安全です。

実行前に SQL を見る

php artisan migrate --pretend
CreateTasksTable: create table `tasks` (`id` bigint unsigned not null auto_increment primary key,
  `title` varchar(255) not null, `created_at` timestamp null, `updated_at` timestamp null)
  default character set utf8mb4 collate 'utf8mb4_unicode_ci'

実際には実行されません。本番に当てる前に、意図しない DROP や大きなテーブルへの ALTER が含まれていないかを必ず確認してください。

状態の確認

php artisan migrate:status
  Migration name .......................................... Batch / Status
  2026_01_01_000000_create_users_table ........................... [1] Ran
  2026_09_07_120000_create_tasks_table ........................... [2] Ran
  2026_09_07_130000_add_status_to_tasks_table ................. Pending

バッチ番号は「同じ migrate 実行でまとめて適用された単位」です。ロールバックはこの単位で戻ります。

戻す

php artisan migrate:rollback              # 直前のバッチをまとめて戻す
php artisan migrate:rollback --step=1     # 1 件だけ戻す
php artisan migrate:rollback --batch=3    # バッチ 3 を戻す
php artisan migrate:reset                 # すべて戻す(down を順に実行)

rollback は「直前の 1 件」ではなく「直前のバッチ全体」を戻します。3 件まとめて migrate していたら 3 件とも戻るので、1 件だけ戻したいときは --step=1 を付けてください。

# 1 件ずつバッチを分けて適用する(戻しやすくなる)
php artisan migrate --step

作り直す

コマンド何をするか本番
migrate未実行のものを適用使う
migrate:rollback直前のバッチを down() で戻す慎重に
migrate:refreshすべて戻してから再実行(down() を通る)使わない
migrate:fresh全テーブルを DROP してから再実行絶対に使わない
php artisan migrate:fresh --seed      # 開発中にデータごと作り直す
php artisan migrate:refresh --step=2  # 直近 2 件だけ作り直す

migrate:freshdown() を通らず、データベース内のテーブルをすべて削除します。マイグレーションで管理していないテーブルも消えます。開発環境専用と考えてください。

本番での実行

# 1. バックアップ
mysqldump -u user -p dbname > backup_$(date +%Y%m%d_%H%M%S).sql

# 2. 何が走るか確認
php artisan migrate:status
php artisan migrate --pretend

# 3. メンテナンスモードにする(必要なら)
php artisan down --secret="xxxxx"

# 4. 実行(本番は非対話なので --force が必須)
php artisan migrate --force

# 5. 戻す
php artisan up

APP_ENV=production のとき、Laravel は「Application In Production!」と表示して Do you really wish to run this command? と聞いてきます。 CI やデプロイスクリプトは入力できないためそこで止まるので、--force を必ず付けます

失敗したとき

SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'tasks' already exists
エラー原因と対処
Table ... already exists手作業で作ったテーブルがある。落として作り直すか、migrations に記録を入れる
SQLSTATE[HY000] [1045] Access denied.env の接続情報。対処はこちら
Specified key was too long古い MySQL。Schema::defaultStringLength(191) を設定する
Cannot add foreign key constraint参照先の型が違う(idbigint unsigned)。参照先を先に作る
doctrine/dbal が必要カラム変更に必要(Laravel 10 以前)。対処はこちら

MySQL は DDL でトランザクションが効きません。1 つのマイグレーションで複数のテーブルを触っていると、途中で失敗して「半分だけ適用された」状態になります。この場合は手作業で状態を戻すか、DB をバックアップから復元してください。

-- 実行済みの記録を確認する
SELECT * FROM migrations ORDER BY id DESC LIMIT 10;

実行時に一緒にやること

php artisan migrate --seed                  # シーダーも走らせる
php artisan migrate --database=second       # 接続先を指定する
php artisan migrate --path=database/migrations/legacy    # 特定のディレクトリだけ
php artisan migrate --isolated              # 複数サーバーで同時実行しないようにする

--isolated は Laravel 9.38 以降で使えます。デプロイ時に複数のサーバーが同時に migrate を実行する構成では、これを付けておくと 1 台だけが実行します。

安全なマイグレーションの書き方

  • 1 マイグレーション 1 目的にする。まとめると失敗時の切り分けができない
  • 大きなテーブルへの ALTER はロック時間を見積もる。オンライン DDL やツールの利用を検討する
  • カラム削除は「使わなくする → 数日後に削除」と 2 段階に分ける
  • down() を必ず書く。書けないなら書けない理由をコメントに残す
  • マイグレーションでデータを大量に更新しない。件数が増えるとデプロイが止まる。シーダーやバッチに分ける

関連

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. 新規プロジェクトの作成
  2. サーバーの起動
  3. マイグレーションファイルの作成
  4. マイグレーションの実行(migrate)
  5. モデルの作成
  6. 全ルートを確認
  7. Laravelのバージョンの確認方法

最近更新/作成されたページ