本文へ移動
Laravel Tips

マイグレーション

データベースの表を作ったり変えたりする手順書「マイグレーション」の作り方・動かし方・戻し方と、カラムの型・修飾子・インデックス・外部キーの一覧を説明します。

マイグレーションは、データベースの表の形を、ファイルに書いて残しておく手順書です。プログラムの変更をバージョン管理(変更の履歴を残すしくみ)するのと同じように、データベースの形の変更も、みんなで共有できます。「プログラムを更新したら、自分のデータベースにも、このカラムを足してね」と仲間に頼む必要がなくなります。

Laravel の Schema ファサード(Schema::create() のように、クラス名と :: で機能を呼べる窓口)は、対応しているどのデータベースでも、同じ書き方で表を作ったり変えたりできます。マイグレーションでは、ふつうこの Schema を使って、表やカラムを作ったり変えたりします。

マイグレーションを作る#

make:migration という Artisan コマンド(php artisan で動かす Laravel のコマンド)で、マイグレーションのファイルを作ります。ファイルは database/migrations に置かれます。ファイル名には日時が入っていて、Laravel はそれで動かす順番を決めます。

bash
php artisan make:migration create_flights_table

Laravel は、マイグレーションの名前から、表の名前と、新しい表を作るかどうかを推測します。表の名前が分かれば、作られたファイルにその表の名前を入れておいてくれます。分からないときは、ファイルの中に自分で書きます。

作るファイルの置き場所を変えたいときは、--path オプションに、アプリの一番上のフォルダからの道すじを渡します。

補足

マイグレーションのひな形(stub)は、書き換えて使えます。方法は Artisan コマンドのページにあります。

マイグレーションをまとめる(スカッシュ)#

アプリを作り進めると、マイグレーションが増え続けて、database/migrations が何百ものファイルでいっぱいになることがあります。そのときは、1つの SQL ファイルにまとめられます。schema:dump コマンドを使います。

bash
php artisan schema:dump

# Dump the current database schema and prune all existing migrations...
php artisan schema:dump --prune

動かすと、Laravel は「スキーマ」(表の作りの全体)のファイルを database/schema に書き出します。ファイルの名前は、データベースの接続の名前になります。そのあと、マイグレーションをまだ1つも動かしていないデータベースで migrate すると、Laravel はまずこのスキーマファイルの SQL を動かします。続けて、まとめに入っていない残りのマイグレーションを動かします。

テストが、ふだんの開発とは別のデータベース接続を使うなら、その接続でも、スキーマファイルを作っておく必要があります。そうしないと、テストがデータベースを作れません。ふだんの接続のあとに、続けて作るとよいでしょう。

bash
php artisan schema:dump
php artisan schema:dump --database=testing --prune

チームの新しい人が、すばやく最初のデータベースを作れるように、スキーマファイルはバージョン管理に入れておきます。

注意

マイグレーションのスカッシュに対応しているのは、MariaDB、MySQL、PostgreSQL、SQLite だけです。データベースに付いている、ターミナルで使う道具(コマンドラインのクライアント)を使って動きます。

マイグレーションの形#

マイグレーションのクラスには、up と down の2つのメソッドがあります。up は、表・カラム・インデックスを新しく足すためのもの、down は、up でしたことを元に戻すためのものです。

どちらも、Laravel のスキーマビルダ(Schema で表の形を組み立てるしくみ)を使って、表の作り方や変え方を書きます。Schema ビルダで使えるメソッドは、このページの後ろで説明します。たとえば、次のマイグレーションは flights という表を作ります。

php
<?php

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

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('flights', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('airline');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::drop('flights');
    }
};

使うデータベース接続を決める#

アプリの既定とは別のデータベース接続を、マイグレーションが使うときは、マイグレーションの $connection プロパティ(クラスの中の変数)に、その接続の名前を入れます。

php
/**
 * The database connection that should be used by the migration.
 *
 * @var string
 */
protected $connection = 'pgsql';

/**
 * Run the migrations.
 */
public function up(): void
{
    // ...
}

マイグレーションを飛ばす#

まだ有効にしていない機能のためのマイグレーションなど、いまは動かしたくないものがあります。そのときは、マイグレーションに shouldRun メソッドを書きます。false を返すと、そのマイグレーションは飛ばされます。

php
use App\Models\Flight;
use Laravel\Pennant\Feature;

/**
 * Determine if this migration should run.
 */
public function shouldRun(): bool
{
    return Feature::active(Flight::class);
}

マイグレーションを動かす#

まだ動かしていないマイグレーションを全部動かすには、migrate コマンドを使います。

bash
php artisan migrate

動かした分と、まだの分を見たいときは、migrate:status を使います。

bash
php artisan migrate:status

migrate に --step を付けると、マイグレーションを1つずつ別の「バッチ」(ひとまとまり)として動かします。あとで migrate:rollback で、1つずつ戻せます。

bash
php artisan migrate --step

動かさずに、動かす SQL だけを見たいときは、--pretend を付けます。

bash
php artisan migrate --pretend

動かすのを1か所だけにする#

何台かのサーバーに公開していて、公開の手順の中で migrate を動かすなら、2台が同時にデータベースを変えようとするのは避けたいはずです。migrate に --isolated を付けます。

--isolated を付けると、Laravel はマイグレーションを動かす前に、鍵(アトミックなロック。途中で割り込まれない鍵)を1つ取ります。鍵の置き場所には、アプリのキャッシュドライバ(キャッシュのしまい方)を使います。鍵がふさがっている間は、ほかから migrate を動かしても、何もしません。ただし、コマンドは「成功」の終了コード(コマンドが終わるときに返す番号)で終わります。

bash
php artisan migrate --isolated

注意

この機能を使うには、アプリの既定のキャッシュドライバが、memcached、redis、dynamodb、database、file、array のどれかである必要があります。また、すべてのサーバーが、同じ1つのキャッシュサーバーを使っている必要があります。

本番で無理やり動かす#

マイグレーションには、データが消えるかもしれない、危ない操作があります。本番のデータベースで、うっかり動かさないように、動かす前に確認を聞かれます。確認なしで動かすには、--force を付けます。

bash
php artisan migrate --force

マイグレーションを戻す#

直前のマイグレーションを戻すには、rollback コマンドを使います。最後の「バッチ」を戻します。1つのバッチには、複数のマイグレーションのファイルが入っていることがあります。

bash
php artisan migrate:rollback

step オプションで、戻す数を決められます。たとえば、次は最後の5つを戻します。

bash
php artisan migrate:rollback --step=5

batch オプションで、特定のバッチを戻せます。数字は、アプリの migrations 表の batch の値です。たとえば、次はバッチ3の全部を戻します。

bash
php artisan migrate:rollback --batch=3

migrate:rollback にも --pretend があり、動かさずに SQL だけを見られます。

bash
php artisan migrate:rollback --pretend

migrate:reset は、アプリの全部のマイグレーションを戻します。

bash
php artisan migrate:reset

マイグレーション関係のコマンドは、次のとおりです。

コマンド 働き
migrate まだ動かしていないマイグレーションを全部動かす
migrate:status 動かした分とまだの分を見る
migrate:rollback 最後のバッチを戻す
migrate:reset 全部のマイグレーションを戻す
migrate:refresh 全部戻してから、もう一度動かす
migrate:fresh 全部の表を消してから、もう一度動かす
schema:dump 表の形を SQL ファイルにまとめる
オプション 働き
--step 1つずつ別のバッチとして動かす(rollback と refresh では戻す数を決める)
--pretend 動かさずに SQL だけを見る
--isolated ロックを取って、動かすのを1か所だけにする
--force 本番でも確認なしで動かす
--batch 戻すバッチの番号を決める
--seed 動かしたあとに、最初のデータも入れる
--database 使うデータベース接続を決める
--prune schema:dump のあとに、いまのマイグレーションのファイルを消す

戻してもう一度動かす#

migrate:refresh は、全部のマイグレーションを戻してから、migrate を動かします。データベース全体を、作り直すのと同じです。

bash
php artisan migrate:refresh

# Refresh the database and run all database seeds...
php artisan migrate:refresh --seed

step で、戻して動かし直す数を決められます。たとえば、最後の5つを戻して、動かし直します。

bash
php artisan migrate:refresh --step=5

全部の表を消して動かす#

migrate:fresh は、データベースの全部の表を消してから、migrate を動かします。

bash
php artisan migrate:fresh

php artisan migrate:fresh --seed

migrate:fresh は、既定では、既定のデータベース接続の表だけを消します。別の接続にしたいときは、--database に、接続の名前を渡します。名前は、アプリの database の設定ファイルに書いてある接続のものです。

bash
php artisan migrate:fresh --database=admin

注意

migrate:fresh は、表の名前の接頭辞(prefix)に関係なく、全部の表を消します。ほかのアプリと共有しているデータベースで開発しているときは、気をつけて使ってください。

表#

表を作る#

新しい表を作るには、Schema の create を使います。引数は2つで、表の名前と、Blueprint(表の設計図)を受け取るクロージャ(名前のない関数)です。

php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

Schema::create('users', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->string('email');
    $table->timestamps();
});

表を作るとき、スキーマビルダのカラムのメソッドは、どれでも使えます。

表やカラムがあるか調べる#

表・カラム・インデックスがあるかは、hasTable・hasColumn・hasIndex で調べられます。

php
if (Schema::hasTable('users')) {
    // The "users" table exists...
}

if (Schema::hasColumn('users', 'email')) {
    // The "users" table exists and has an "email" column...
}

if (Schema::hasIndex('users', ['email'], 'unique')) {
    // The "users" table exists and has a unique index on the "email" column...
}

接続と表のオプション#

アプリの既定でないデータベース接続で操作するときは、connection を使います。

php
Schema::connection('sqlite')->create('users', function (Blueprint $table) {
    $table->id();
});

表を作るときの、ほかの設定をするメソッドもあります。

メソッド 働き
engine 表のストレージエンジン(データのしまい方)を決める(MariaDB / MySQL)
charset 表の文字コードを決める(MariaDB / MySQL)
collation 表の照合順序(文字の並べ方の決まり)を決める(MariaDB / MySQL)
temporary 一時的な表にする
comment 表にコメントを付ける(MariaDB / MySQL / PostgreSQL)
php
Schema::create('users', function (Blueprint $table) {
    $table->engine('InnoDB');

    // ...
});
php
Schema::create('users', function (Blueprint $table) {
    $table->charset('utf8mb4');
    $table->collation('utf8mb4_unicode_ci');

    // ...
});

temporary を使うと、表は「一時的」になります。一時的な表は、いまのデータベース接続からだけ見えて、接続を閉じると自動で消えます。

php
Schema::create('calculations', function (Blueprint $table) {
    $table->temporary();

    // ...
});
php
Schema::create('calculations', function (Blueprint $table) {
    $table->comment('Business calculations');

    // ...
});

表を変える#

すでにある表を変えるには、Schema の table を使います。create と同じく、引数は表の名前と、Blueprint を受け取るクロージャです。カラムやインデックスを足せます。

php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

Schema::table('users', function (Blueprint $table) {
    $table->integer('votes');
});

表の名前を変える・消す#

表の名前を変えるには、rename を使います。

php
use Illuminate\Support\Facades\Schema;

Schema::rename($from, $to);

表を消すには、drop か dropIfExists を使います。dropIfExists は、あるときだけ消します。

php
Schema::drop('users');

Schema::dropIfExists('users');

注意

表の名前を変える前に、その表の外部キー制約(表どうしのつながりの決まり)に、マイグレーションの中で、はっきり名前を付けておいてください。Laravel が決まりに沿って付けた名前のままだと、外部キーの名前が、古い表の名前を指したままになります。

カラム#

カラムを作る#

すでにある表にカラムを足すには、Schema::table を使います。Blueprint を受け取るクロージャの中で、カラムを足します。

php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

Schema::table('users', function (Blueprint $table) {
    $table->integer('votes');
});

カラムの型の一覧#

スキーマビルダの Blueprint には、データベースに足せるカラムの型ごとに、メソッドがあります。下の表に、全部を並べます。「〜相当」は、そのデータベースの型にあたるという意味です。

真偽値(はい・いいえ)#

メソッド 説明
boolean BOOLEAN 相当のカラムを作る
php
$table->boolean('confirmed');

文字・文章#

メソッド 説明
char 長さを決めた CHAR 相当のカラム
longText LONGTEXT 相当のカラム
mediumText MEDIUMTEXT 相当のカラム
string 長さを決めた VARCHAR 相当のカラム
text TEXT 相当のカラム
tinyText TINYTEXT 相当のカラム
php
$table->char('name', length: 100);

$table->string('name', length: 100);

$table->text('description');

$table->mediumText('description');

$table->longText('description');

$table->tinyText('notes');

MySQL と MariaDB では、text の仲間に binary の文字コードを付けると、BLOB の仲間のカラムになります。

書き方 できるカラム
text('data')->charset('binary') BLOB
mediumText('data')->charset('binary') MEDIUMBLOB
longText('data')->charset('binary') LONGBLOB
tinyText('data')->charset('binary') TINYBLOB
php
$table->text('data')->charset('binary'); // BLOB

$table->mediumText('data')->charset('binary'); // MEDIUMBLOB

$table->longText('data')->charset('binary'); // LONGBLOB

$table->tinyText('data')->charset('binary'); // TINYBLOB

数#

メソッド 説明
bigIncrements 自動で増える UNSIGNED BIGINT 相当の主キーのカラム
bigInteger BIGINT 相当のカラム
decimal 全体の桁数と小数の桁数を決めた DECIMAL 相当のカラム
double DOUBLE 相当のカラム
float 精度を決めた FLOAT 相当のカラム
id bigIncrements の別名。既定のカラム名は id
increments 自動で増える UNSIGNED INTEGER 相当の主キーのカラム
integer INTEGER 相当のカラム
mediumIncrements 自動で増える UNSIGNED MEDIUMINT 相当の主キーのカラム
mediumInteger MEDIUMINT 相当のカラム
smallIncrements 自動で増える UNSIGNED SMALLINT 相当の主キーのカラム
smallInteger SMALLINT 相当のカラム
tinyIncrements 自動で増える UNSIGNED TINYINT 相当の主キーのカラム
tinyInteger TINYINT 相当のカラム
unsignedBigInteger UNSIGNED BIGINT 相当のカラム
unsignedInteger UNSIGNED INTEGER 相当のカラム
unsignedMediumInteger UNSIGNED MEDIUMINT 相当のカラム
unsignedSmallInteger UNSIGNED SMALLINT 相当のカラム
unsignedTinyInteger UNSIGNED TINYINT 相当のカラム
php
$table->id();

$table->bigIncrements('id');

$table->increments('id');

$table->mediumIncrements('id');

$table->smallIncrements('id');

$table->tinyIncrements('id');

$table->bigInteger('votes');

$table->integer('votes');

$table->mediumInteger('votes');

$table->smallInteger('votes');

$table->tinyInteger('votes');

$table->unsignedBigInteger('votes');

$table->unsignedInteger('votes');

$table->unsignedMediumInteger('votes');

$table->unsignedSmallInteger('votes');

$table->unsignedTinyInteger('votes');

$table->decimal('amount', total: 8, places: 2);

$table->double('amount');

$table->float('amount', precision: 53);

id は、カラム名を渡せば、id 以外の名前にもできます。

日付・時刻#

メソッド 説明
dateTime 小数点以下の秒の精度を選べる DATETIME 相当のカラム
dateTimeTz タイムゾーン付きの DATETIME 相当のカラム(精度を選べる)
date DATE 相当のカラム
time 精度を選べる TIME 相当のカラム
timeTz タイムゾーン付きの TIME 相当のカラム(精度を選べる)
timestamp 精度を選べる TIMESTAMP 相当のカラム
timestampTz タイムゾーン付きの TIMESTAMP 相当のカラム(精度を選べる)
timestamps created_at と updated_at の TIMESTAMP 相当のカラムを作る(精度を選べる)
timestampsTz タイムゾーン付きで、created_at と updated_at を作る(精度を選べる)
softDeletes Eloquent の「ソフト削除」(消さずに印を付ける)に使う、空でもよい deleted_at の TIMESTAMP 相当のカラム
softDeletesTz タイムゾーン付きの softDeletes
year YEAR 相当のカラム
php
$table->dateTime('created_at', precision: 0);

$table->dateTimeTz('created_at', precision: 0);

$table->date('created_at');

$table->time('sunrise', precision: 0);

$table->timeTz('sunrise', precision: 0);

$table->timestamp('added_at', precision: 0);

$table->timestampTz('added_at', precision: 0);

$table->timestamps(precision: 0);

$table->timestampsTz(precision: 0);

$table->softDeletes('deleted_at', precision: 0);

$table->softDeletesTz('deleted_at', precision: 0);

$table->year('birth_year');

バイナリ(そのままのデータ)#

メソッド 説明
binary BLOB 相当のカラム
php
$table->binary('photo');

MySQL・MariaDB・SQL Server では、length と fixed を渡すと、VARBINARY か BINARY 相当のカラムになります。

php
$table->binary('data', length: 16); // VARBINARY(16)

$table->binary('data', length: 16, fixed: true); // BINARY(16)

JSON#

メソッド 説明
json JSON 相当のカラム
jsonb JSONB 相当のカラム
php
$table->json('options');

$table->jsonb('options');

SQLite では、どちらも TEXT のカラムになります。

UUID と ULID#

UUID と ULID は、重ならないように作る長い ID の種類です。

メソッド 説明
ulid ULID 相当のカラム
uuid UUID 相当のカラム
ulidMorphs {カラム名}_type(VARCHAR)と {カラム名}_id(CHAR(26))の2つを足す
uuidMorphs {カラム名}_type(VARCHAR)と {カラム名}_id(CHAR(36))の2つを足す
nullableUlidMorphs ulidMorphs と同じで、空でもよいカラムになる
nullableUuidMorphs uuidMorphs と同じで、空でもよいカラムになる
php
$table->ulid('id');

$table->uuid('id');

$table->ulidMorphs('taggable');

$table->uuidMorphs('taggable');

$table->nullableUlidMorphs('taggable');

$table->nullableUuidMorphs('taggable');

ulidMorphs と uuidMorphs は、ULID や UUID の ID を使う、ポリモーフィックなリレーション(1つの表が、いろいろな表につながるしくみ)のために、必要なカラムをまとめて足す便利なメソッドです。上の例では、taggable_type と taggable_id ができます。

位置のデータ(空間)#

メソッド 説明
geography 空間の種類と SRID(空間参照系の ID)を決めた GEOGRAPHY 相当のカラム
geometry 空間の種類と SRID を決めた GEOMETRY 相当のカラム
php
$table->geography('coordinates', subtype: 'point', srid: 4326);

$table->geometry('positions', subtype: 'point', srid: 0);

補足

空間の型に対応しているかは、データベースのドライバによります。データベースの説明書を見てください。PostgreSQL を使うなら、geography や geometry を使う前に、PostGIS という拡張を入れる必要があります。

表どうしのつながり#

メソッド 説明
foreignId UNSIGNED BIGINT 相当のカラム
foreignIdFor モデルのクラスに合わせた {カラム名}_id を足す。型はモデルのキーによって UNSIGNED BIGINT・CHAR(36)・CHAR(26) のどれか
foreignUlid ULID 相当のカラム
foreignUuid UUID 相当のカラム
foreignUuidFor モデルのクラスに合わせた、UUID の {カラム名}_id を足す
morphs {カラム名}_type(VARCHAR)と {カラム名}_id を足す。_id の型は、モデルのキーによって UNSIGNED BIGINT・CHAR(36)・CHAR(26) のどれか
nullableMorphs morphs と同じで、空でもよいカラムになる
php
$table->foreignId('user_id');

$table->foreignIdFor(User::class);

$table->foreignUlid('user_id');

$table->foreignUuid('user_id');

$table->foreignUuidFor(User::class);

$table->morphs('taggable');

$table->nullableMorphs('taggable');

morphs も、ポリモーフィックなリレーションのためのカラムを足す便利なメソッドです。上の例では、taggable_type と taggable_id ができます。

そのほかの型#

メソッド 説明
enum 決めた値だけを入れられる ENUM 相当のカラム
set 決めた値の組を入れられる SET 相当のカラム
macAddress MAC アドレス(機器の番号)用のカラム。PostgreSQL には専用の型があり、ほかは文字のカラム
ipAddress VARCHAR 相当のカラム。PostgreSQL では INET のカラム
rememberToken 「ログインしたままにする」トークン用の、空でもよい VARCHAR(100) 相当のカラム
vector vector 相当のカラム
php
$table->enum('difficulty', ['easy', 'hard']);

$table->set('flavors', ['strawberry', 'vanilla']);

$table->macAddress('device');

$table->ipAddress('visitor');

$table->rememberToken();

enum には、許す値を手で書く代わりに、Enum::cases() も使えます。

php
use App\Enums\Difficulty;

$table->enum('difficulty', Difficulty::cases());

vector は、ベクトル(意味を数の並びにしたもの)を入れるカラムです。

php
$table->vector('embedding', dimensions: 1536);

ベクトルのカラムに対応しているのは、pgvector 拡張を使った PostgreSQL と、MariaDB 11.7 以上です。PostgreSQL では、vector のカラムを作る前に、pgvector を読み込んでおく必要があります。

php
Schema::ensureVectorExtensionExists();

ベクトルの近さで探す問い合わせを速くするために、そのカラムにベクトルのインデックスを足せます。vector のカラムで index を呼ぶと、コサイン距離(向きの近さ)を使うベクトルのインデックスができます。

php
$table->vector('embedding', dimensions: 1536)->index();

カラムの修飾子#

カラムを足すとき、上の型のほかに、いろいろな「修飾子」を付けられます。たとえば、カラムを「空でもよい」にするには、nullable を使います。

php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

Schema::table('users', function (Blueprint $table) {
    $table->string('email')->nullable();
});

使える修飾子は次のとおりです。インデックスの修飾子は含みません。

修飾子 説明
->after('column') 別のカラムの「あと」に置く(MariaDB / MySQL)
->autoIncrement() INTEGER のカラムを、自動で増える主キーにする
->charset('utf8mb4') カラムの文字コードを決める(MariaDB / MySQL)
->collation('utf8mb4_unicode_ci') カラムの照合順序を決める
->comment('my comment') カラムにコメントを付ける(MariaDB / MySQL / PostgreSQL)
->default($value) カラムの「既定の値」を決める
->first() 表の「いちばん前」に置く(MariaDB / MySQL)
->from($integer) 自動で増える値の、最初の値を決める(MariaDB / MySQL / PostgreSQL)
->instant() 「instant」操作でカラムを足す・変える(MySQL)
->invisible() SELECT * から、カラムを見えなくする(MariaDB / MySQL)
->lock($mode) カラムの操作のロックの種類を決める(MySQL)
->nullable($value = true) カラムに NULL(値なし)を入れてよいことにする
->storedAs($expression) 保存される生成カラムを作る(MariaDB / MySQL / PostgreSQL / SQLite)
->unsigned() INTEGER のカラムを UNSIGNED(マイナスなし)にする(MariaDB / MySQL)
->using($expression) カラムの型を変えるときの、変換の式を決める(PostgreSQL)
->useCurrent() TIMESTAMP の既定の値を CURRENT_TIMESTAMP(いまの日時)にする
->useCurrentOnUpdate() 行を更新したとき、TIMESTAMP を CURRENT_TIMESTAMP にする(MariaDB / MySQL)
->virtualAs($expression) 保存されない仮想の生成カラムを作る(MariaDB / MySQL / SQLite)
->generatedAs($expression) シーケンスの設定を決めた、アイデンティティカラム(自動で番号を出すカラム)を作る(PostgreSQL)
->always() アイデンティティカラムで、入力より、シーケンスの値を優先するかを決める(PostgreSQL)

既定の値の式#

default には、値か、Illuminate\Database\Query\Expression を渡せます。Expression を使うと、Laravel は値を引用符で囲まないので、データベース独自の関数が使えます。JSON のカラムに既定の値を入れたいときに、とくに便利です。

php
<?php

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

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('flights', function (Blueprint $table) {
            $table->id();
            $table->json('movies')->default(new Expression('(JSON_ARRAY())'));
            $table->timestamps();
        });
    }
};

注意

既定の値の式に対応しているかは、データベースのドライバ、データベースの版、カラムの型によります。データベースの説明書を見てください。

カラムの並び順#

MariaDB と MySQL では、after を使って、すでにあるカラムのあとに、カラムを足せます。

php
$table->after('password', function (Blueprint $table) {
    $table->string('address_line1');
    $table->string('address_line2');
    $table->string('city');
});

instant 操作#

MySQL では、カラムの定義に instant をつなげると、MySQL の「instant」アルゴリズム(やり方)で、カラムを足したり変えたりします。このやり方なら、表を作り直さずに、ある種の変更ができ、表が大きくても、ほぼ一瞬で終わります。

php
$table->string('name')->nullable()->instant();

instant でカラムを足せるのは、表のいちばん後ろだけなので、instant は after や first と一緒には使えません。また、すべての型や操作に対応しているわけではありません。合わない操作だと、MySQL がエラーを出します。

どの操作が instant に対応しているかは、MySQL の説明書で確かめます。

DDL のロック#

DDL は、表の形を作ったり変えたりする SQL のことです。MySQL では、カラム・インデックス・外部キーの定義に lock をつなげると、表の形を変えている間に、表へどんな鍵(ロック)をかけるかを決められます。ロックの種類は4つあります。

種類 働き
none 読むことも書くことも、同時にできる
shared 読むことは同時にできるが、書くことはできない
exclusive 同時のアクセスを、すべて止める
default MySQL がいちばんよい種類を選ぶ
php
$table->string('name')->lock('none');

$table->index('email')->lock('shared');

合わない種類を選ぶと、MySQL がエラーを出します。lock は instant と一緒に使うこともできます。

php
$table->string('name')->instant()->lock('none');

カラムを変える#

change は、すでにあるカラムの型や性質を変えます。たとえば string のカラムを大きくしたいときに使えます。name カラムを 25 から 50 に大きくする例です。カラムの新しい形を書いて、change を呼びます。

php
Schema::table('users', function (Blueprint $table) {
    $table->string('name', 50)->change();
});

カラムを変えるとき、残したい修飾子は、全部、書き直す必要があります。書かなかったものは、なくなります。たとえば、unsigned・default・comment を残すには、それぞれを呼びます。

php
Schema::table('users', function (Blueprint $table) {
    $table->integer('votes')->unsigned()->default(1)->comment('my comment')->change();
});

change は、カラムのインデックスは変えません。変えたいときは、インデックスの修飾子で、足したり消したりします。

php
// Add an index...
$table->bigIncrements('id')->primary()->change();

// Drop an index...
$table->char('postal_code', 10)->unique(false)->change();

PostgreSQL でカラムを変える#

PostgreSQL でカラムの型を変えるときは、using で、いまの値を新しい型に変える式を決められます。

php
Schema::table('users', function (Blueprint $table) {
    $table->date('birthday')->using('birthday::date')->change();
});

カラムの名前を変える#

カラムの名前を変えるには、スキーマビルダの renameColumn を使います。

php
Schema::table('users', function (Blueprint $table) {
    $table->renameColumn('from', 'to');
});

カラムを消す#

カラムを消すには、スキーマビルダの dropColumn を使います。

php
Schema::table('users', function (Blueprint $table) {
    $table->dropColumn('votes');
});

カラム名の配列を渡すと、いくつものカラムを一度に消せます。

php
Schema::table('users', function (Blueprint $table) {
    $table->dropColumn(['votes', 'avatar', 'location']);
});

カラムを消す近道のメソッド#

よくあるカラムを消すための、便利なメソッドがあります。

メソッド 説明
$table->dropMorphs('morphable'); morphable_type と morphable_id のカラムを消す
$table->dropRememberToken(); remember_token のカラムを消す
$table->dropSoftDeletes(); deleted_at のカラムを消す
$table->dropSoftDeletesTz(); dropSoftDeletes() の別名
$table->dropTimestamps(); created_at と updated_at のカラムを消す
$table->dropTimestampsTz(); dropTimestamps() の別名

インデックス#

インデックスは、本の索引のように、データを速く探すための目印です。

インデックスを作る#

スキーマビルダは、いろいろな種類のインデックスに対応しています。次の例は、email カラムを作り、値が重ならない(unique)ようにします。カラムの定義に unique をつなげると、インデックスもできます。

php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

Schema::table('users', function (Blueprint $table) {
    $table->string('email')->unique();
});

カラムを作ったあとで、インデックスを作ることもできます。スキーマビルダの unique を呼び、インデックスを付けるカラムの名前を渡します。

php
$table->unique('email');

カラム名の配列を渡すと、複合インデックス(複数のカラムをまとめたインデックス)になります。

php
$table->index(['account_id', 'created_at']);

インデックスを作るとき、Laravel は、表の名前・カラムの名前・インデックスの種類から、インデックスの名前を自動で付けます。2つ目の引数に、自分で名前を渡すこともできます。

php
$table->unique('email', 'unique_email');

インデックスの種類#

Blueprint には、対応している種類ごとにメソッドがあります。どれも、2つ目の引数に、インデックスの名前を渡せます。省くと、表とカラムの名前、種類から、名前が決まります。

メソッド 説明
$table->primary('id'); 主キーを足す
$table->primary(['id', 'parent_id']); 複合の主キーを足す
$table->unique('email'); 値が重ならないインデックスを足す
$table->index('state'); ふつうのインデックスを足す
$table->fullText('body'); 全文インデックスを足す(MariaDB / MySQL / PostgreSQL)
$table->fullText('body')->language('english'); 言語を決めた全文インデックスを足す(PostgreSQL)
$table->spatialIndex('location'); 空間インデックスを足す(SQLite 以外)
$table->vectorIndex('embedding'); ベクトルインデックスを足す(MariaDB / PostgreSQL)

止めずにインデックスを作る(オンライン)#

既定では、大きな表にインデックスを作っている間、表がロックされて、読むことも書くことも止まる場合があります。PostgreSQL と SQL Server では、インデックスの定義に online をつなげると、表をロックせずに作れます。作っている間も、アプリは読み書きを続けられます。

php
$table->unique('email')->online();

PostgreSQL では、インデックスを作る文に CONCURRENTLY が付きます。SQL Server では、WITH (online = on) が付きます。

MySQL では、インデックスや外部キーの定義に inplace をつなげると、その操作に INPLACE アルゴリズム(表をまるごと写し直さずに、その場で変えるやり方)を使わせられます。

php
$table->index('email')->inplace();

$table->foreign('user_id')->references('id')->on('users')->inplace();

inplace は、lock と組み合わせて、ロックのかけ方も決められます。

php
$table->index('email')->inplace()->lock('none');

外部キーの操作で inplace を使うときは、外部キーのチェックを、止めておく必要があります。

どの操作が INPLACE やロックの種類に対応しているかは、MySQL の説明書で確かめます。

インデックスの名前を変える#

インデックスの名前を変えるには、Blueprint の renameIndex を使います。1つ目に、いまの名前、2つ目に、新しい名前を渡します。

php
$table->renameIndex('from', 'to');

インデックスを消す#

インデックスを消すには、インデックスの名前を指定します。既定では、Laravel が、表の名前・カラムの名前・種類から、名前を付けています。例を並べます。

メソッド 説明
$table->dropPrimary('users_id_primary'); users 表の主キーを消す
$table->dropUnique('users_email_unique'); users 表の、値が重ならないインデックスを消す
$table->dropIndex('geo_state_index'); geo 表の、ふつうのインデックスを消す
$table->dropFullText('posts_body_fulltext'); posts 表の全文インデックスを消す
$table->dropSpatialIndex('geo_location_spatialindex'); geo 表の空間インデックスを消す(SQLite 以外)
$table->dropVectorIndex('documents_embedding_vectorindex'); documents 表のベクトルインデックスを消す

インデックスを消すメソッドにカラム名の配列を渡すと、表の名前・カラム・種類から、決まりどおりの名前が作られます。

php
Schema::table('geo', function (Blueprint $table) {
    $table->dropIndex(['state']); // Drops index 'geo_state_index'
});

外部キー制約#

外部キー制約は、表どうしのつながりが壊れないように、データベースで守らせる決まりです。たとえば、posts 表に user_id のカラムを作り、users 表の id を指すようにします。

php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

Schema::table('posts', function (Blueprint $table) {
    $table->unsignedBigInteger('user_id');

    $table->foreign('user_id')->references('id')->on('users');
});

この書き方は長いので、Laravel には、決まりを使った、短い書き方があります。カラムを foreignId で作ると、上の例を次のように書き直せます。

php
Schema::table('posts', function (Blueprint $table) {
    $table->foreignId('user_id')->constrained();
});

foreignId は、UNSIGNED BIGINT 相当のカラムを作ります。constrained は、Laravel の名前の決まりから、指す先の表とカラムを決めます。表の名前が決まりと合わないときは、constrained に表の名前を渡します。作るインデックスの名前も渡せます。

php
Schema::table('posts', function (Blueprint $table) {
    $table->foreignId('user_id')->constrained(
        table: 'users', indexName: 'posts_user_id'
    );
});

制約の「on delete」(指す行が消えたとき)と「on update」(指す行が変わったとき)の動きも決められます。

php
$table->foreignId('user_id')
    ->constrained()
    ->onUpdate('cascade')
    ->onDelete('cascade');

これらの動きには、読みやすい別の書き方もあります。

メソッド 説明
$table->cascadeOnUpdate(); 更新を、つながった行にも伝える
$table->restrictOnUpdate(); 更新を禁止する
$table->nullOnUpdate(); 更新されたら、外部キーの値を NULL にする
$table->noActionOnUpdate(); 更新のときは何もしない
$table->cascadeOnDelete(); 削除を、つながった行にも伝える
$table->restrictOnDelete(); 削除を禁止する
$table->nullOnDelete(); 削除されたら、外部キーの値を NULL にする
$table->noActionOnDelete(); つながった子の行があれば、削除させない

ほかのカラムの修飾子は、constrained より前に呼びます。

php
$table->foreignId('user_id')
    ->nullable()
    ->constrained();

外部キーを消す#

外部キーを消すには、dropForeign に、消す外部キー制約の名前を渡します。外部キー制約の名前は、インデックスと同じ決まりで付きます。つまり、表の名前とカラムの名前に、「_foreign」を付けたものです。

php
$table->dropForeign('posts_user_id_foreign');

外部キーのカラムの名前を入れた配列を渡すこともできます。Laravel の名前の決まりで、外部キー制約の名前に直されます。

php
$table->dropForeign(['user_id']);

外部キー制約を入り切りする#

マイグレーションの中で、外部キー制約を有効にしたり、無効にしたりできます。

メソッド 働き
Schema::enableForeignKeyConstraints() 外部キー制約を有効にする
Schema::disableForeignKeyConstraints() 外部キー制約を無効にする
Schema::withoutForeignKeyConstraints() クロージャの中だけ、外部キー制約を無効にする
php
Schema::enableForeignKeyConstraints();

Schema::disableForeignKeyConstraints();

Schema::withoutForeignKeyConstraints(function () {
    // Constraints disabled within this closure...
});

注意

SQLite は、既定では外部キー制約が無効です。SQLite を使うときは、マイグレーションで外部キーを作る前に、データベースの設定で、外部キーの対応を有効にしてください。

イベント#

マイグレーションの操作ごとに、イベント(「起きた」という知らせ)が出ます。SchemaDumped と SchemaLoaded 以外は、どれも Illuminate\Contracts\Database\Events\MigrationEvent インターフェイス(クラスが持つべきメソッドを決めた約束)を満たしています。

クラス 説明
Illuminate\Database\Events\DatabaseRefreshed migrate:fresh か migrate:refresh が終わった
Illuminate\Database\Events\MigrationsStarted マイグレーションのバッチを動かす直前
Illuminate\Database\Events\MigrationsEnded マイグレーションのバッチが終わった
Illuminate\Database\Events\MigrationStarted マイグレーション1つを動かす直前
Illuminate\Database\Events\MigrationEnded マイグレーション1つが終わった
Illuminate\Database\Events\NoPendingMigrations マイグレーションのコマンドが、動かす分がないと分かった
Illuminate\Database\Events\SchemaDumped データベースのスキーマのダンプが終わった
Illuminate\Database\Events\SchemaLoaded すでにあるスキーマのダンプを読み込んだ

関連するページ#

公式ドキュメント(英語)

2026年10月5日時点の内容をもとに、日本語でまとめています。

ページの一覧