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

# データベースマイグレーション

> Laravelのマイグレーション機能を使ってデータベーススキーマをバージョン管理する方法を解説します。

## マイグレーションとは

マイグレーションはデータベースのバージョン管理のようなものです。
チームがアプリケーションのデータベーススキーマ定義を共有・管理できます。

ソースコードを pull した後に「ローカルのデータベースにカラムを手動で追加してください」とチームメンバーに伝えなければならない場面を経験したことがあるでしょう。
マイグレーションはその問題を解決します。

マイグレーションファイルは `database/migrations` ディレクトリに格納されます。
各ファイル名にはタイムスタンプが含まれており、Laravelがマイグレーションの実行順序を決定するために使われます。

## マイグレーションファイルの作成

`make:migration` Artisanコマンドで新しいマイグレーションファイルを生成します。

```shell theme={null}
php artisan make:migration create_posts_table
```

マイグレーション名から Laravelはテーブル名を推測し、適切なスタブを生成します。
`create_posts_table` という名前であれば、`posts` テーブルを作成するコードがあらかじめ用意されます。

## マイグレーションの構造

マイグレーションクラスは `up` と `down` の2つのメソッドを持ちます。

* `up` メソッド：テーブル・カラム・インデックスをデータベースに追加します。
* `down` メソッド：`up` の操作を元に戻します。ロールバック時に呼ばれます。

```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::create('posts', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->text('body');
            $table->boolean('published')->default(false);
            $table->timestamps();
        });
    }

    /**
     * マイグレーションを元に戻す
     */
    public function down(): void
    {
        Schema::dropIfExists('posts');
    }
};
```

## 主なカラム定義メソッド

`Blueprint` クラスには多くのカラム型が用意されています。

| メソッド | 説明 |
| - | - |
| `$table->id()` | 自動増分の主キー（`bigIncrements('id')` の別名） |
| `$table->string('name')` | VARCHAR相当のカラム（デフォルト255文字） |
| `$table->text('body')` | TEXTカラム |
| `$table->integer('count')` | INTEGERカラム |
| `$table->boolean('active')` | TINYINTで真偽値を格納 |
| `$table->timestamp('published_at')` | TIMESTAMPカラム |
| `$table->timestamps()` | `created_at` と `updated_at` をまとめて追加 |
| `$table->softDeletes()` | 論理削除用の `deleted_at` カラムを追加 |
| `$table->foreignId('user_id')` | 外部キー用の `BIGINT UNSIGNEDカラム` |

### カラム修飾子

カラム定義にはメソッドチェーンで修飾子を追加できます。

```php theme={null}
$table->string('email')->unique();
$table->string('name')->nullable();
$table->integer('votes')->default(0);
$table->string('title')->after('id'); // 指定カラムの後に配置
```

### ベクターカラムとインデックス

`vector` メソッドは、埋め込みベクトルを保存する `vector` カラムを作成します。`dimensions` には、使用する埋め込みプロバイダーの出力次元数を指定してください。

```php theme={null}
$table->vector('embedding', dimensions: 1536);
```

ベクターカラムは `pgvector` 拡張を使用する PostgreSQL 接続と、MariaDB 11.7以降で利用できます。PostgreSQLでは、ベクターカラムを作成する前に `pgvector` を有効化してください。

```php theme={null}
Schema::ensureVectorExtensionExists();
```

ベクターの類似検索を高速化するには、`vector` カラムに `index` を追加します。このインデックスは cosine distance を使います。

```php theme={null}
$table->vector('embedding', dimensions: 1536)->index();
```

既存のベクターインデックスを削除する場合は `dropVectorIndex` を使います。

```php theme={null}
$table->dropVectorIndex('documents_embedding_vectorindex');
```

### オンラインでのインデックス作成

大きなテーブルでインデックスを作成すると、通常はインデックスの構築中にテーブルがロックされ、読み書きが待たされることがあります。MySQLでは、インデックスや外部キーの定義に `inplace` 修飾子を付けると、`INPLACE` アルゴリズムを使って操作できます。

```php theme={null}
Schema::table('users', function (Blueprint $table) {
    $table->index('email')->inplace();
    $table->foreign('team_id')
        ->references('id')
        ->on('teams')
        ->inplace();
});
```

`inplace` は `lock` 修飾子と組み合わせて、操作中のテーブルロックを指定できます。`none` を指定すると、MySQLが許可する操作では読み書きを継続できます。

```php theme={null}
Schema::table('users', function (Blueprint $table) {
    $table->index('email')->inplace()->lock('none');
});
```

この機能はMySQL専用です。利用する操作が `INPLACE` アルゴリズムと指定したロックモードに対応しているかは、[MySQLのオンラインDDL操作のドキュメント](https://dev.mysql.com/doc/refman/8.0/en/innodb-online-ddl-operations.html)で確認してください。外部キー操作で `inplace` を使う場合は、あらかじめ外部キー制約を無効にする必要があります。

## マイグレーションの実行

`migrate` コマンドで未実行のマイグレーションをすべて実行します。

```shell theme={null}
php artisan migrate
```

実行済みのマイグレーションと未実行のマイグレーションを確認するには `migrate:status` を使います。

```shell theme={null}
php artisan migrate:status
```

<Warning>
  本番環境でマイグレーションを実行すると確認プロンプトが表示されます。
  確認なしで実行したい場合は `--force` フラグを使いますが、データが失われる操作もあるため慎重に行ってください。
</Warning>

## ロールバック

直近のマイグレーションバッチを取り消すには `migrate:rollback` を使います。

```shell theme={null}
php artisan migrate:rollback
```

特定のステップ数だけロールバックするには `--step` オプションを指定します。

```shell theme={null}
# 直近5件のマイグレーションをロールバック
php artisan migrate:rollback --step=5
```

すべてのマイグレーションをロールバックしてから再実行するには `migrate:refresh` を使います。

```shell theme={null}
php artisan migrate:refresh
```

<Info>
  `migrate:refresh` はすべてのテーブルを作り直すため、既存のデータは失われます。
  開発中のデータベースリセットに便利です。
</Info>

## 実践例：postsテーブルの作成

ブログ投稿を管理する `posts` テーブルを例に、一連の流れを確認します。

### 1. マイグレーションファイルの生成

```shell theme={null}
php artisan make:migration create_posts_table
```

### 2. マイグレーションの編集

`database/migrations/xxxx_xx_xx_xxxxxx_create_posts_table.php` を開いて編集します。

```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::create('posts', function (Blueprint $table) {
            $table->id();
            $table->foreignId('user_id')->constrained()->cascadeOnDelete();
            $table->string('title');
            $table->text('body');
            $table->boolean('published')->default(false);
            $table->timestamp('published_at')->nullable();
            $table->timestamps();
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('posts');
    }
};
```

### 3. マイグレーションの実行

```shell theme={null}
php artisan migrate
```

実行後、データベースに `posts` テーブルが作成されます。

### 4. カラムを後から追加する

テーブル作成後に新しいカラムを追加したい場合は、既存のマイグレーションを編集せず、新しいマイグレーションを作成します。

```shell theme={null}
php artisan make:migration add_excerpt_to_posts_table
```

```php theme={null}
public function up(): void
{
    Schema::table('posts', function (Blueprint $table) {
        $table->string('excerpt')->nullable()->after('title');
    });
}

public function down(): void
{
    Schema::table('posts', function (Blueprint $table) {
        $table->dropColumn('excerpt');
    });
}
```

<Tip>
  既存のマイグレーションファイルを直接編集するのは避けましょう。
  他のメンバーや本番環境との整合性が崩れます。
  変更は常に新しいマイグレーションとして追加します。
</Tip>

## マイグレーションイベント

マイグレーション操作のたびに[イベント](/jp/events)が発行されます。すべてのイベントは `Illuminate\Database\Events\MigrationEvent` を継承しています。

| クラス | 説明 |
| - | - |
| `Illuminate\Database\Events\DatabaseRefreshed` | `migrate:refresh` コマンドの完了後 |
| `Illuminate\Database\Events\MigrationsStarted` | マイグレーションのバッチが実行される直前 |
| `Illuminate\Database\Events\MigrationsEnded` | マイグレーションのバッチの完了後 |
| `Illuminate\Database\Events\MigrationStarted` | 単一のマイグレーションが実行される直前 |
| `Illuminate\Database\Events\MigrationEnded` | 単一のマイグレーションの完了後 |
| `Illuminate\Database\Events\NoPendingMigrations` | マイグレーションコマンドが未実行のマイグレーションなしと判定した時 |
| `Illuminate\Database\Events\SchemaDumped` | データベーススキーマダンプの完了後 |
| `Illuminate\Database\Events\SchemaLoaded` | 既存のスキーマダンプのロード後 |

たとえば `MigrationsEnded` イベントをリッスンして、マイグレーション完了後にキャッシュをクリアすることができます。

```php theme={null}
use Illuminate\Database\Events\MigrationsEnded;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Event;

Event::listen(MigrationsEnded::class, function () {
    Cache::flush();
});
```

## 次のステップ

<Card title="データベースシーディング" icon="seedling" href="/jp/seeding">
  マイグレーションで作成したテーブルにサンプルデータを投入する方法を学びます。
</Card>

<Card title="Eloquent入門" icon="database" href="/jp/eloquent">
  マイグレーションで作成したテーブルをEloquent ORMで操作する方法を学びます。
</Card>


## Related topics

- [Laravel AI SDK](/jp/ai-sdk.md)
- [データベースシーディング](/jp/seeding.md)
- [Testbench Workbenchでパッケージ開発を進める](/jp/advanced/package-workbench.md)
- [パッケージのマイグレーション公開と更新](/jp/advanced/package-migrations.md)
- [データベーステスト](/jp/database-testing.md)


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