Laravel開発においてデータベース構造(スキーマ)を定義・管理するために欠かせないのがマイグレーション(Migration)機能です。
「SQLを手動で実行してテーブルを作成・変更している」「チーム開発で誰がどのカラムを追加したか分からなくなる」「本番環境へのDB反映でミスが起きた」といった課題は、マイグレーションを正しく使いこなすことで一掃できます。
本記事では、Laravelのマイグレーションの仕組みから、ファイルの作成・スキーマ定義・実行・ロールバック・カラム変更・実務でのベストプラクティスまで、初心者にもわかりやすく徹底解説します(Laravel 11 / 12 対応)。
- 1. Laravelのマイグレーションとは?仕組みとメリット
- 2. 事前準備:データベース接続の設定
- 3. マイグレーションファイルの作成方法(make:migration)
- 4. テーブル定義の基本:よく使うカラム型と修飾子
- 5. マイグレーションの実行(php artisan migrate)
- 6. マイグレーションのロールバックとリセット
- 7. カラムの追加・変更・リネーム・削除(実践テクニック)
- 8. マイグレーションの適用状態を確認する(migrate:status)
- 9. 実務で失敗しないためのベストプラクティス
- 10. よくあるエラーと原因・対処法
- まとめ:マイグレーションをマスターして安全なDB管理を
- 関連リファレンス記事
- 関連記事
1. Laravelのマイグレーションとは?仕組みとメリット
マイグレーションとは、一言で言えば「データベーススキーマのバージョン管理システム(GitのDB版)」です。
通常、テーブルの作成やカラム変更はSQL文(CREATE TABLE や ALTER TABLE)で行いますが、LaravelではPHPコードでスキーマを定義し、Artisanコマンド1つでデータベースに反映できます。
マイグレーションを使う4つのメリット
- チーム全体でスキーマを完全同期できる: Gitでマイグレーションファイルを共有し、
php artisan migrateを実行するだけで、全開発者のローカル環境が同じ状態になります。 - 変更履歴がコードとして残る: 誰がいつどんなテーブルやカラムを追加・変更したかがファイルとして記録されます。
- 安全にロールバック(巻き戻し)ができる: 変更前の状態に戻す
downメソッドを用意しておくことで、トラブル時に直前の状態へ即座に切り戻せます。 - DBエンジンに依存しない記述: MySQL、PostgreSQL、SQLite、SQL Serverなど、異なるRDBMSでも同じPHPコードでスキーマを構築できます。
migrations テーブルの役割
Laravelはマイグレーションを実行すると、データベース内に自動的に migrations という管理テーブルを作成します。
このテーブルには「実行済みのマイグレーションファイル名」と「実行バッチ番号(batch)」が記録されます。Laravelはここを参照することで、「まだ適用されていない新しいマイグレーションファイルだけ」を自動判別して実行します。
2. 事前準備:データベース接続の設定
マイグレーションを実行する前に、プロジェクトルートの .env ファイルでデータベース接続情報が正しく設定されているか確認します。
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=my_laravel_app
DB_USERNAME=root
DB_PASSWORD=secret
※ SQLiteを使用する場合は DB_CONNECTION=sqlite とし、database/database.sqlite ファイルを作成しておくだけで利用可能です。
3. マイグレーションファイルの作成方法(make:migration)
マイグレーションファイルを新規作成するには、Artisanコマンドの make:migration を使用します。
新規テーブル作成用のファイルを生成する
php artisan make:migration create_posts_table
ファイル名が create_テーブル名_table の形式になっていると、Laravelは自動的にテーブル作成用のスケルトンコードを生成してくれます。
既存テーブル変更用のファイルを生成する
すでに存在するテーブルにカラムを追加・変更する場合は、--table オプションを指定します。
php artisan make:migration add_status_to_posts_table --table=posts
マイグレーションファイルの構造
生成されたファイルは database/migrations/2026_01_01_000000_create_posts_table.php のように、先頭に実行日時プレフィックスが付与されます。Laravel 11以降では以下のような「無名クラス(Anonymous Migration)」の構文が標準です。
<?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::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('content');
$table->timestamps();
});
}
/**
* マイグレーションのロールバック(巻き戻し)
*/
public function down(): void
{
Schema::dropIfExists('posts');
}
};
up()メソッド:php artisan migrate実行時に呼び出される処理(テーブル作成やカラム追加など)を記述します。down()メソッド:php artisan migrate:rollback実行時に呼び出される処理(テーブル削除やカラム削除など、up()の逆操作)を記述します。
4. テーブル定義の基本:よく使うカラム型と修飾子
Blueprint $table オブジェクトを使用して、テーブルのカラム定義を行います。
よく使うカラム型一覧
| メソッド | 生成される型(MySQL例) | 用途・説明 |
|---|---|---|
$table->id(); | BIGINT AUTO_INCREMENT (PK) | 自動増分の主キー(id カラム) |
$table->string('title', 100); | VARCHAR(100) | 短い文字列(第2引数で長さ指定可能。省略時は255) |
$table->text('content'); | TEXT | 長文テキスト(記事本文など) |
$table->integer('views'); | INT | 整数値 |
$table->unsignedBigInteger('user_id'); | BIGINT UNSIGNED | 符号なし大きな整数(外部キーなど) |
$table->boolean('is_published'); | TINYINT(1) / BOOLEAN | 真偽値(フラグ) |
$table->decimal('price', 10, 2); | DECIMAL(10, 2) | 固定小数点数(金額など) |
$table->date('published_at'); | DATE | 日付(YYYY-MM-DD) |
$table->dateTime('reserved_at'); | DATETIME | 日時(YYYY-MM-DD HH:MM:SS) |
$table->json('settings'); | JSON | JSONデータ |
$table->timestamps(); | TIMESTAMP | created_at と updated_at を自動生成 |
$table->softDeletes(); | TIMESTAMP (nullable) | 論理削除用の deleted_at を生成 |
カラム修飾子(属性の設定)
カラム型の後ろにメソッドチェーンをつなぐことで、NULL許容やデフォルト値などの属性を設定できます。
// NULLを許可する
$table->string('sub_title')->nullable();
// デフォルト値を設定する
$table->string('status')->default('draft');
$table->integer('priority')->default(0);
// ユニーク制約(一意)を付与する
$table->string('email')->unique();
// 特定カラムの後ろに配置する(MySQLのみ)
$table->string('phone')->after('email');
// カラムにコメントを付与する
$table->string('code')->comment('商品コード');
外部キー制約の書き方
Laravelでは foreignId メソッドを使うことで、簡潔かつ安全に外部キー制約を定義できます。
// usersテーブルのidを参照する外部キー(CASCADE削除付き)
$table->foreignId('user_id')
->constrained()
->cascadeOnDelete();
constrained() を引数なしで呼ぶと、カラム名(user_id)から自動的に参照先テーブル(users)とカラム(id)を推測してくれます。親レコード削除時に連動して削除する場合は cascadeOnDelete()、NULLにする場合は nullOnDelete() を指定します。
5. マイグレーションの実行(php artisan migrate)
マイグレーションファイルを記述したら、データベースに反映します。
php artisan migrate
未適用のファイルが順番に実行され、ターミナルに以下のような実行結果が出力されます。
Running migrations.
2026_01_01_000000_create_posts_table ........................... 15.20ms DONE
便利な実行オプション
- SQLを事前確認する(
--pretend):php artisan migrate --pretend
実際にクエリを実行せず、発行される生SQL文を画面に表示します。安全確認に便利です。 - マイグレーション後に初期データを投入する(
--seed):php artisan migrate --seed
マイグレーション完了後、自動的に Seeder を実行します。 - 本番環境で確認なしに強制実行する(
--force):php artisan migrate --force
本番環境(APP_ENV=production)では確認プロンプトが表示されるため、CI/CDパイプラインや自動デプロイスクリプトでは--forceが必須です。
※ コマンドの詳細なオプション仕様は php artisan migrate の使い方とオプション一覧 も参照してください。
6. マイグレーションのロールバックとリセット
マイグレーションの実行を取り消したい、または環境を作り直したい場合に使用するコマンド群です。
直前のマイグレーションを取り消す(migrate:rollback)
# 直近1回(1バッチ)のマイグレーションをロールバック
php artisan migrate:rollback
# 直近3つのマイグレーションファイルをロールバック
php artisan migrate:rollback --step=3
migrate:rollback は、最後に実行されたバッチに含まれるマイグレーションの down() メソッドを実行します。詳細な挙動は migrate:rollbackの使い方ガイド をご確認ください。
開発環境を一発で初期化する(migrate:fresh)
ローカル開発中にスキーマを一から作り直したい場合、最もよく使われるのが migrate:fresh です。
# 全テーブルをDROPして全マイグレーションを再実行
php artisan migrate:fresh
# テストデータ(Seeder)も一緒に投入
php artisan migrate:fresh --seed
マイグレーション管理コマンド比較表
| コマンド | 動作内容 | 主な使用シーン |
|---|---|---|
migrate | 未適用のマイグレーションを実行 | 通常のスキーマ更新、本番デプロイ |
migrate:rollback | 直前バッチの down() を実行して取り消し | ミスしたマイグレーションの切り戻し |
migrate:fresh | 全テーブルをDROP してから全実行 | ローカル開発でのDBリフレッシュ(推奨) |
migrate:refresh | すべての down() を実行後に全実行 | down() の動作検証 |
migrate:reset | すべての down() を実行(再実行はしない) | DBを空に戻したいとき |
migrate:status | マイグレーションの適用状態を一覧表示 | 未適用の確認、トラブル調査 |
7. カラムの追加・変更・リネーム・削除(実践テクニック)
本番稼働後やチーム開発では、既存テーブルを変更するマイグレーションが日常的に発生します。必ず Schema::table を使用して新しいマイグレーションファイルを作成します。
① カラムを追加する
php artisan make:migration add_published_at_to_posts_table --table=posts
public function up(): void
{
Schema::table('posts', function (Blueprint $table) {
$table->dateTime('published_at')->nullable()->after('content');
});
}
public function down(): void
{
Schema::table('posts', function (Blueprint $table) {
$table->dropColumn('published_at');
});
}
② カラムの型や属性を変更する(change)
既存カラムのサイズ拡張やNULL許容化を行うには、change() メソッドを使います。
public function up(): void
{
Schema::table('posts', function (Blueprint $table) {
// title の長さを 255 から 500 に拡張し、nullable に変更
$table->string('title', 500)->nullable()->change();
});
}
public function down(): void
{
Schema::table('posts', function (Blueprint $table) {
// 元の定義(NOT NULL、長さ255)に戻す
$table->string('title', 255)->nullable(false)->change();
});
}
💡 Laravel 11 / 12 のポイント:
以前のLaravelではchange()の利用にdoctrine/dbalパッケージが必須でしたが、Laravel 11以降はフレームワーク標準でカラム変更をサポートするようになり、追加パッケージのインストールが不要になりました。
③ カラム名を変更する(renameColumn)
public function up(): void
{
Schema::table('posts', function (Blueprint $table) {
$table->renameColumn('title', 'post_title');
});
}
public function down(): void
{
Schema::table('posts', function (Blueprint $table) {
$table->renameColumn('post_title', 'title');
});
}
④ カラムを削除する(dropColumn)
public function up(): void
{
Schema::table('posts', function (Blueprint $table) {
$table->dropColumn('is_draft');
});
}
public function down(): void
{
Schema::table('posts', function (Blueprint $table) {
// ロールバック時にカラムを復元する
$table->boolean('is_draft')->default(true);
});
}
8. マイグレーションの適用状態を確認する(migrate:status)
現在どのマイグレーションが適用済みで、どれが未適用かを確認するには migrate:status を実行します。
php artisan migrate:status
+------+-------------------------------------------------------+-------+
| Ran? | Migration | Batch |
+------+-------------------------------------------------------+-------+
| Yes | 2026_01_01_000000_create_users_table | 1 |
| Yes | 2026_01_01_000001_create_posts_table | 1 |
| No | 2026_01_02_000000_add_published_at_to_posts_table | |
+------+-------------------------------------------------------+-------+
Ran? が No になっているファイルが、次回 php artisan migrate 実行時に適用されるマイグレーションです。
9. 実務で失敗しないためのベストプラクティス
- 適用済みのマイグレーションファイルを直接編集しない
すでにGitにプッシュしたり本番環境に適用したファイルを書き換えても、migrationsテーブルに記録済みのマイグレーションは再実行されません。スキーマを変更したいときは、必ず新しいマイグレーションファイルを作成してください。 down()メソッドを必ず実装する
カラム追加やテーブル作成を行った際は、対になるロールバック処理(dropColumnやdropIfExists)を必ずdown()に書いておきましょう。これが抜けていると、デプロイ失敗時の緊急切り戻しができなくなります。- 本番運用の大規模テーブル変更はロックに注意する
何百万件ものデータがあるテーブルに対してALTER TABLEを実行すると、テーブルロックが発生してWebサービスが一時停止する恐れがあります。事前に実行計画や所要時間を確認し、段階的な移行(カラム追加 → アプリ側切り替え → 旧カラム削除)を行いましょう。 - 外部キーの型と符号(unsigned)を一致させる
主キーが$table->id()(BIGINT UNSIGNED)の場合、参照側の外部キーも$table->foreignId('user_id')や$table->unsignedBigInteger('user_id')で型と符号を完全に一致させる必要があります。
10. よくあるエラーと原因・対処法
| エラーメッセージ | 主な原因 | 対処法 |
|---|---|---|
Base table or view already exists | 作成しようとしたテーブルが既にDBに存在する | DBを手動操作したか、ファイルが重複。migrate:status を確認し、不要ならテーブルを削除するか Schema::hasTable で存在判定を追加。 |
Column already exists | 追加しようとしたカラムが既にテーブルに存在する | 過去に直接カラムを追加していないか確認。新規マイグレーションの定義を見直す。 |
Foreign key constraint is incorrectly formed | 外部キーの型不一致、または参照先テーブルが未作成 | マイグレーションファイルの実行順序(タイムスタンプ)を確認し、親テーブルが先に作られるように調整。型の符号(unsigned)を一致させる。 |
SQLSTATE[HY000] [1049] Unknown database | 指定されたデータベースが存在しない | .env の DB_DATABASE 設定を確認し、DBサーバー上にデータベースを作成する。 |
Nothing to migrate. | 未適用のマイグレーションが存在しない | 全ファイルが適用済みです。新しいファイルを作ったのに反映されない場合は、配置ディレクトリやファイル名を確認。 |
まとめ:マイグレーションをマスターして安全なDB管理を
Laravelのマイグレーションは、チーム開発や本番運用におけるデータベース管理を安全かつ効率的に行うための基盤です。
- ファイルの作成は
php artisan make:migration - 適用の実行は
php artisan migrate - 切り戻しは
php artisan migrate:rollback - ローカル開発のリフレッシュは
php artisan migrate:fresh --seed - 既存テーブルの変更は
Schema::tableとchange()
それぞれのコマンドの役割と up() / down() の関係性をしっかり押さえて、日々のLaravel開発に役立ててください。

コメント