prisma-next-migrations について
prisma-next-migrationsは、データ契約の変更をデータベースに適用する開発者向けのPrisma Nextスキルです。クイック更新とレビュー可能なマイグレーションの両方を扱い、データ変換の作成や失敗からの復旧も説明します。
主な機能
- 01データベースマイグレーションの計画と適用
- 02クイック更新と正式なマイグレーションの選択
- 03データ変換プレースホルダーの補完
- 04マニフェストとハッシュの再生成
- 05マイグレーションエラーとドリフトの診断
活用シーン
- 01ローカル開発データベースへの契約変更の適用
- 02共有ブランチ向けのレビュー可能なマイグレーション作成
- 03新しいフィールドのデータバックフィル作成
- 04ハッシュ不一致や部分適用からの復旧
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ prisma/ prisma-next --skill prisma-next-migrationsインストール後、Claude Code で/prisma-next-migrationsを入力して読み込まれたか確認します。
詳細
Prisma Next — マイグレーションの作成
データコントラクトを編集すると、Prisma Next がマイグレーションを計画します。データ変換は必要に応じて記述します。
ユーザーモデルは次の3ステップです。
- データコントラクトを編集します。 (
prisma-next-contract) - Prisma Next がマイグレーションを計画します。 ← このスキル
- データ変換が必要な場合は、
migration.tsを編集して自分で出力します。 ← このスキル
コントラクトを変更したら、その変更をデータベースに反映する方法を選びます。このスキルでは、2つの経路(db update と migration plan + migrate)、マイグレーションパッケージのコントラクト、migration.ts の作成 API、およびループを離れずに対処できる障害モードについて説明します。
対象。 マイグレーションの作成は Postgres と Mongo を第一級でサポートしています。CLI は prisma-next.config.ts(prisma-next init --target … の実行時に設定)からターゲットを読み取ります。マイグレーションコマンドは --target フラグを受け付けません。必要なターゲットに合わせた設定を使用してください。以下の例では、ターゲットによって異なるインポート、マーカー、ファクトリー、トランザクションの動作を明記しています。
使用する場面
- ユーザーがコントラクトを編集し、変更を DB に適用したい場合。
- ユーザーがデータ変換を含むマイグレーションを作成したい場合。
- ユーザーが保留中のマイグレーションをローカル DB に対して実行したい場合。
MIGRATION.HASH_MISMATCH、PN-MIG-2001(未入力のプレースホルダー)、または部分的に適用されたマイグレーションが発生した場合。- ユーザーが次のような内容に言及している場合:migrate、migration、db push、db update、
prisma migrate dev、prisma migrate deploy、drift、hash mismatch、data backfill。
使用しない場面
- デプロイ時やマージ時にどのマイグレーションが 実行されるか を確認したい場合、または参照と不変条件を管理したい場合 →
prisma-next-migration-review。 - コントラクトを編集したい場合 →
prisma-next-contract。 - 単一の構造化エラーエンベロープを詳しく確認したい場合 →
prisma-next-debug。
主要な概念
db update(クイックパス)。 出力されたコントラクトを読み込み、稼働中の DB との差分を取り、変更を適用します。省略可能な--dry-runを指定すると、実行せずに計画を表示します。破壊的操作の確認は対話形式で行われます(自動承認するには-yを指定します)。マイグレーションディレクトリは書き込みません。 データ変換が必要な操作はこのパスでは処理されません。db updateはdata操作クラスを完全に除外し、データ変換が必要な場合はそこで処理を終了します。他の人と履歴を共有していないデータベース(ローカル開発用 DB)に対してのみ使用してください。migration plan(正式パス)。 出力されたコントラクトを読み込み、ディスク上のマイグレーショングラフの先頭との差分を取り、migrations/app/<YYYYMMDDTHHMM>_<snake_slug>/に新しいマイグレーションパッケージを書き込みます。データ変換が必要な操作がある場合、パッケージのmigration.tsには、入力するplaceholder(...)呼び出しが含まれます。- マイグレーションパスの
app/セグメントは、利用側アプリケーションのコントラクトスペース ID です。 自分が作成するマイグレーションはすべてmigrations/app/に格納されます。コントラクトが依存する拡張機能には、それぞれ独自の兄弟ディレクトリ(migrations/<extension-space-id>/)が割り当てられます。これらは拡張機能パッケージによって管理されるため、そこに書き込むことはありません。アプリレベルの設定に対して初めてmigration plan/db initを実行すると、app/セグメントが自動的に作成されます。 - マイグレーションパッケージのファイル(各
migrations/app/<dir>/内):migration.json— マニフェスト(メタデータ +migrationHash)。ops.json— 正規の操作リスト。コンテンツアドレス方式で管理され、migrationHashはこの内容から計算されます。migration.ts— TypeScript の作成用ソース。migration plan(またはmigration new)によってフレームワークが生成します。特定の箇所を編集し(下記の プレースホルダーを埋める を参照)、実行してops.json/migration.jsonを再出力します。
- コントラクトのスナップショット。
migration.tsは、マイグレーションパッケージ内のファイルではなく、共有のコンテンツアドレスストアにあるmigrations/snapshots/<hex>/contract.json+contract.d.tsから、マイグレーションの開始時と終了時のコントラクトをインポートします(<hex>はコントラクトの 64 桁の 16 進数ストレージハッシュです)。 - 自己出力。
node migrations/app/<dir>/migration.tsを実行すると、(編集されている可能性のある)TS ソースからops.jsonとmigration.jsonが再生成されます。編集後に既存のマイグレーションパッケージを更新する方法としてサポートされているのは、これだけです。 migration.tsの構造。 フレームワークが生成します。Migrationを継承するクラス(Mongo では@prisma-next/family-mongo/migrationから、Postgres では@prisma-next/postgres/migrationを介して再エクスポートされたものからインポートします。下記のフレーミングブロックを参照)で、ファクトリー呼び出しの値を配列で返すoperationsゲッターを持ちます。ファイルの末尾にはMigrationCLI.run(import.meta.url, M)があり、実行すると自己出力します。placeholder(slot)。 データ変換が必要な箇所に、プランナーが生成されるmigration.tsに出力するセンチネルです(Mongo では@prisma-next/errors/migrationから、Postgres では@prisma-next/postgres/migrationのインポートから)。出力時にplaceholder(...)を呼び出すと、PN-MIG-2001未入力のマイグレーションプレースホルダー がスローされます。ユーザーは() => placeholder(...)のアロー関数を実際のクエリプランクロージャ(Postgres)に置き換えるか、dataTransform({ check, run })のソース(Mongo。「プレースホルダーを埋める」を参照)を入力してから、自己出力します。this.dataTransform(endContract, name, { check, run })。 データ変換ファクトリーです。checkは、1 行でも存在すれば「作業が残っている」ことを示す行セットクエリです。runは、バックフィルを実行する 1 つ以上の変更クエリです。どちらも、endContractに対して構築されたクエリプランを返す遅延クロージャーです。ランナーは事前チェックでcheckをEXISTS(...)に、事後チェックでNOT EXISTS(...)にラップします。これにより、同じクロージャーで「作業が残っていること」と「作業が完了していること」の両方を検証します。pendingPlaceholders。migration planの JSON 結果に含まれるブール値フィールドです。trueは、パッケージは書き込まれたものの、未入力のプレースホルダーが残っていることを意味します。migration.tsを編集して自己出力するまで、migrateはPN-MIG-2001をスローします。migrationHash。 マイグレーションパッケージのコンテンツアドレス方式の ID です。migration.jsonに保存されているハッシュが、ディスク上のファイルから再計算したハッシュと一致しない場合、MIGRATION.HASH_MISMATCHが発生します(ほとんどの場合、自己出力せずに誰かがmigration.tsを編集しています)。- マーカー。 「このデータベースは、スペース Y のコントラクトハッシュ X の状態にある」ことを記録します。Postgres:
prisma_contract.markerの行。Mongo:_prisma_migrationsコレクション内のドキュメント(スペースをキーとして使用)。各マイグレーションは、そのスペースのスキーマ検証に合格した後、マーカーを 1 回進めます。db signは現在のコントラクトハッシュからマーカーを書き込みますが、スキーマ検証に合格した場合に限ります(稼働中のスキーマがコントラクトと一致しないデータベースには署名しません)。 - 適用の原子性。 Postgres: 各マイグレーションは
BEGIN ... COMMIT内で実行されます。失敗した場合、Postgres はロールバックし、マーカーは前のマイグレーションのtoハッシュのままです。Mongo: DDL 操作(createCollection、createIndex、collMod、setValidation、…)は複数ドキュメントにまたがるトランザクションでラップされません。ランナーは操作を適用し、稼働中のスキーマを移行先のコントラクトと照合して検証し、検証に合格した場合のみマーカーを進めます(スペースをまたいだ再開が可能です。MongoDB ファミリーのドキュメントを参照)。通常の DDL とdataTransformのフローは一貫性を保ちます。マイグレーションの途中で失敗した場合の部分的な状態は、無視せずdb verify/db schemaで診断します。 - 操作クラス。 各操作には
operationClassが宣言されており、additive、widening、data、destructiveのいずれかです。CLI はこれらを計画プレビューと JSON 出力に表示します。long-runningクラスはなく、フレームワークはCREATE INDEX CONCURRENTLYを出力しません。操作はトランザクション内で実行されます。
migration.ts は手書きではなく、フレームワークによってレンダリングされます
migrations/<space-id>/<timestamp>/migration.ts 配下のファイル(独自のアプリでは、<space-id> は常に app/ です)は、フレームワークによってレンダリングされます。コントラクトが変更されるたびに prisma-next migration plan が内容の入ったパッケージを書き込み、操作を直接記述したい場合は prisma-next migration new が空のスキャフォールドを書き込みます。これらのファイルを一から作成する必要はありません。フレームワークが残した特定の箇所を編集します。主に、placeholder("<slot>") センチネル(Postgres)を置き換えるか、dataTransform({ check, run }) パイプラインのスロット(Mongo)を埋めてから、セルフ出力します。
Postgres のレンダリング済みインポートは @prisma-next/postgres/migration(SQLite プロジェクトでは @prisma-next/sqlite/migration)を参照します。
Mongo のレンダリング済みインポートでは、Migration 基底クラスに @prisma-next/family-mongo/migration を、操作ファクトリー(createIndex、dataTransform、…)に @prisma-next/target-mongo/migration を使用します。MigrationCLI は @prisma-next/cli/migration-cli から取得します。
どちらのターゲットでも、レンダリング済みのインポート行はフレームワークが管理するものとして扱ってください。
- そのままの場所に残してください。別の
@prisma-next/<…>パスに書き換えないでください。フレームワークのレンダラーが正規の形式を定めており、手作業で変更すると、次回パッケージが再レンダリングまたはセルフ出力されたときに元に戻され(MIGRATION.HASH_MISMATCHが発生する可能性もあります)。 - ファクトリーシンボルを追加する必要がある場合は、別の
@prisma-next/...サブパスから新たにインポートするのではなく、既存のレンダリング済みインポート行に追加してください(Postgres:@prisma-next/postgres/migration、Mongo:@prisma-next/target-mongo/migration)。 - 「ユーザーコードは
@prisma-next/<target>からのみインポートする」という規約は、独自のモジュール(クエリ、ランタイムのセットアップ、コントラクトの記述)に適用されます。フレームワークがレンダリングするmigration.tsスキャフォールドはフレームワーク側のものであり、ユーザー側のものではありません。この規則は、このファイルに限り適用されません。
対応する診断コード
| コード | 発生元 | 対応 |
|---|---|---|
PN-MIG-2001 未入力のマイグレーションプレースホルダー | 出力時に placeholder(...) をスロー | migration.ts を開き、名前付きの placeholder("<slot>") 呼び出しを実際のクエリクロージャーに置き換えて、セルフ出力します。 |
PN-MIG-2002 migration.ts が見つからない | マイグレーションパッケージの読み取り | パッケージの形式が正しくありません。バージョン管理から復元するか、新しいパッケージを作成するために prisma-next migration new を実行してください。 |
PN-MIG-2003 無効なデフォルトエクスポート | migration.ts の読み込み | ファイルのデフォルトエクスポートが Migration サブクラスでもファクトリー関数でもありません。プランナーが出力したスキャフォールドをバージョン管理から復元するか、クリーンなパッケージを作成するために migration plan を再実行してください。 |
PN-MIG-2005 dataTransform のコントラクト不一致 | データ変換クエリプランの構築 | クエリビルダーが、this.dataTransform(...) に渡された endContract とは異なるコントラクト参照を使ってインスタンス化されました。モジュールスコープでインポートした endContract を両方に使用してください。 |
MIGRATION.HASH_MISMATCH マイグレーションパッケージが破損しています | migrate(またはパッケージの読み取り) | セルフ出力せずに ops.json / migration.json が編集されました。node migrations/app/<dir>/migration.ts を実行して再出力してから、migrate を再実行してください。 |
PN-RUN-3002 ハッシュ不一致 | db verify | マーカーとコントラクトのハッシュが一致しません(Postgres: prisma_contract.marker、Mongo: _prisma_migrations)。DB のコントラクトバージョンが、コードが想定するものと異なります。マイグレーションを実行して先に進めるか、DB が正しく、手動修正後にマーカーが古くなっている場合は db sign を実行してください。 |
PN-RUN-3001 データベースに署名がありません | マーカーを必要とするすべてのコマンド | DB にまだマーカーがありません。空のデータベースをベースライン化するには prisma-next db init --db <url> を、現在のコントラクトを直接適用するには db update --db <url> を実行してください。 |
決定 — どの方法を選びますか?
| 状況 | 方法 | 理由 |
|---|---|---|
| ローカル開発中で、スキーマが流動的 | db update | 高速で対話的であり、マイグレーションファイルも不要です。 |
| 他の開発者と共有するブランチ | migration plan + migrate | 再実行可能で、レビューでき、コンテンツハッシュで識別されます。 |
| 本番環境に到達するあらゆる変更 | migration plan + migrate | 本番環境では、レビュー済みでハッシュ化されたマイグレーションを実行する必要があります。 |
| バックフィルが必要なカラムの追加 | migration plan(placeholderを書き込みます)、migration.tsを編集し、自分で生成してからmigrate | db updateではデータ変換を作成できません。正式な方法では作成できます。 |
| ドリフトからの復旧(DBがコントラクトと乖離) | 手動修正後にdb sign、またはPNで修正を計画できる場合はmigration plan | どちらが正しいかによって異なります。下記のドリフトからの復旧を参照してください。 |
開発から出荷への移行(db refパターン)
例 — ローカルでdb updateを使って反復し、最初の正式なマイグレーションを公開します。
pnpm prisma-next db init --db $DATABASE_URL
pnpm prisma-next contract emit && pnpm prisma-next db update --db $DATABASE_URL
pnpm prisma-next contract emit && pnpm prisma-next migration plan --name add_feature
pnpm prisma-next migrate --db $DATABASE_URL
pnpm prisma-next db verify --db $DATABASE_URL
db refはmigrations/app/refs/db.jsonにある名前付きポインターで、内容は{ hash, invariants }だけです。プロジェクトの開発用データベースがどのコントラクトハッシュまで更新されたかを記録します。これは、計画時に接続を開かずに「ローカルDBはどの状態か」を示す、オフラインプランナーの代替情報です。指定されたコントラクトは、そのハッシュに対応するmigrations/snapshots/<hex>/contract.jsonにある共有コンテンツアドレスストアから解決されます。これは、すべてのマイグレーショングラフノードが解決に使うものと同じストアです。
db init / db updateが書き込むもの。 プロジェクトのデフォルトの--db URLに対して実行した場合(明示的な--dbフラグを指定しない場合)、どちらのコマンドもdb refを暗黙的に進めます。コマンド実行後のコントラクトIRをスナップショットストアに存在しない場合のみ書き込み、その後refのポインターを書き込みます。--advance-ref <name>でref名を変更できます。--db <non-default-url>を指定した場合、--advance-refを明示しない限りrefの更新は抑制されます。別のデータベースを調整することは、このプロジェクトの開発状態をチェックポイントに記録することとは異なります。
ディスク上の構成は、ポインターだけです。
migrations/app/refs/
└── db.json # { "hash": "<hex>", "invariants": [] }
開発で反復した後の最初のmigration plan。 migration planは、--fromのデフォルト値としてdb refを使います。ディスク上のマイグレーショングラフがまだ空で、db refがnull以外のハッシュを指し、そのハッシュに対応するストアエントリーが存在する場合(通常、db updateを1回以上実行した後)、プランナーは1つではなく2つのバンドルを生成します。
- ベースライン:
null → from-hash(from-hashをグラフノードとして追加します) - 差分:
from-hash → current_contract
どちらも1回の実行でディスクに書き込まれます。git statusには新しいディレクトリが2つ表示されます。その後、migrateはベースラインを通るパスを見つけ、差分を適用します。これにより、単一バンドルの計画がまだグラフノードになっていないハッシュを参照し、適用不能なマイグレーションが生成されるという、開発から出荷への移行時の落とし穴を防ぎます(適用時にMIGRATION.PATH_UNREACHABLEが発生します)。
フラグ指定忘れの落とし穴。 グラフが空でなくなった後、デフォルトのdb refがグラフの先端を越えた状態になることがあります(反復中にマイグレーションをコミットしないまま、db updateのたびにrefが進んだ場合)。次に暗黙のデフォルトでmigration planを実行すると、MIGRATION.HASH_NOT_IN_GRAPHを返して拒否し、グラフノードを指す到達可能なrefを表示します。
計画時にMIGRATION.HASH_NOT_IN_GRAPHが表示された場合の復旧方法:
# Option A — plan from a graph node explicitly
pnpm prisma-next migration plan --from production --name my_change
# Option B — realign the db ref to a graph-node hash, then plan with the default
pnpm prisma-next ref set db <graph-node-hash>
pnpm prisma-next migration plan --name my_change
db refのポインター自体がなく、そのハッシュもグラフノードではない場合(MIGRATION.SNAPSHOT_MISSING)、ref set db <hash>で作成するか、db update --advance-ref dbで進めます。
通常のmigrate実行後。 migrateはdb refを暗黙的に進めません(本番環境を想定したコマンドでは明示的な指定が必要です)。ライブマーカーは進みますが、refは遅れたままになる場合があります。db update(すでに最新の場合、DBへの変更はありません)を実行するか、同じ呼び出しでmigrate --advance-ref dbを指定して更新してください。
パスを切り替えるタイミング。 個人開発用データベースでスキーマが頻繁に変わる間は、db update を使用します。変更にレビュー可能で再実行可能なマイグレーションが必要になったら、migration plan と migrate に切り替えます。通常は、PR を作成する前、または共有環境に変更を加える前です。db ref が両者をつなぎます。開発中の反復状態をディスクに保存するため、最初の正式なプランでどこまで進んだかを把握できます。
グラフノードのルール(プラン作成時)。 from 端点として使用するハッシュ(明示的な --from、デフォルトの db ref、または ref 名)は、グラフが空でなくなった後は、すでにディスク上のマイグレーショングラフのノードでなければなりません。自動ベースラインによる 2 バンドルの生成は例外です。この処理は、グラフが空で、ref から解決された from が null ではなく、ストアにエントリーがある場合にのみ適用されます。ref のポインターがなく、ハッシュもグラフノードではない場合、プランは代わりに MIGRATION.SNAPSHOT_MISSING で拒否されます。
適用時の補完ルール。 migrate は DDL の実行前にライブマーカーを読み取ります。マーカーのハッシュがグラフノードでない場合、コマンドは MIGRATION.MARKER_MISMATCH で拒否されます。これにより、オフラインのプランナーでは検出できないドリフトを捕捉します。これは、マーカーがたどっているパスから外れている場合に、ランナーがグラフをたどる途中で後から発生する MIGRATION.MARKER_NOT_IN_HISTORY とは別のエラーです。診断の全一覧については、prisma-next-migration-review を参照してください。
db はデフォルトの ref 名であり、予約名ではありません。フレームワークは次の開発サイクルでこれを上書きします。明示的に ref set db <hash> を実行しても構いませんが、デフォルト URL に対して db update を実行すると、その後に置き換えられることにご注意ください。
正式な詳細:Migration System § Contract resolution through the snapshot store、§ migration plan、§ Recovery affordances、ADR 218 — Refs with paired contract snapshots and universal graph-node invariant(TML-2629。ペアのスナップショットに関する部分は後続の内容に置き換えられています。ADR の Status 注記を参照してください)、およびADR 240 — Contract snapshots live in a content-addressed store。
ワークフロー — db update(クイックパス)
考え方:db update はライブ DB に対して適用先(emitted contract)を解決し、差分を適用します。--dry-run でプレビューできます。破壊的操作は、-y または --no-interactive を指定しない限り、対話形式で確認を求められます。このパスでは data クラスの操作をすべて除外します。差分にデータ変換が必要な場合、db update は計画エラーで失敗するため、migration plan に切り替えて変換を作成してください。
コントラクトを編集した後に実行します:
pnpm prisma-next contract emit
# Postgres: --db postgresql://...
# Mongo: --db mongodb://... (dev scaffolds often need ?replicaSet=rs0)
pnpm prisma-next db update --db $DATABASE_URL --dry-run
pnpm prisma-next db update --db $DATABASE_URL
db update は成功時にスキーマを検証してマーカーを進めるため、続けて db verify を実行する必要はありません。正常に完了した場合、後続の db verify は冗長です。独立した診断が必要な場合にのみ db verify を使用してください(コントラクトと DB の検証を参照)。
JSON 出力を確認して、次の操作を判断します:
pnpm prisma-next db update --db $DATABASE_URL --json
JSON には、各 operationClass を含む plan.operations[] と、(適用モードの場合)execution.operationsExecuted および適用後の marker.storageHash が含まれます。破壊的操作が原因でコマンドが失敗した場合、エンベロープの meta.destructiveOperations[] に、削除される予定だったものが正確に一覧表示されます。
ワークフロー — migration plan + migrate(正式な手順)
概要:migration plan は新しいマイグレーションパッケージをディスク上に作成します。プランナーがデータ変換を必要と判断した場合、パッケージは保留中となり、migration.ts には入力するまで placeholder(...) 呼び出しが残ります。migrate は、保留中のすべてのパッケージをグラフ順にトランザクションで実行します。
変更を計画します。
pnpm prisma-next contract emit
pnpm prisma-next migration plan --name <snake_slug>
結果を確認します。JSON の形式から、クエリ可能なシグナルを確認できます。
dir— 新しいパッケージのパス(例:migrations/app/20260515T1200_add_user_email/)。pendingPlaceholders—migration.tsにplaceholder(...)呼び出しがまだ含まれている場合はtrue。operations[].operationClass—destructiveおよびdata操作を特定するための値。preview.statements— ファミリーに依存しないテキスト形式のプレビュー。
パッケージを確認します。
pnpm prisma-next migration show
pnpm prisma-next migration show <dirName-or-migrationHash-prefix>
migration show は単一のマイグレーションパッケージを表示します。すべてのコントラクトスペースにわたって実行されるマイグレーションの順序付きリストを確認するには、migrate --show を使います。
# Online: reads the live DB marker as the origin.
pnpm prisma-next migrate --show --db $DATABASE_URL
# Offline: hypothetical path from any ref or hash.
pnpm prisma-next migrate --show --from <hash-or-ref> --to <hash-or-ref>
migrate --show は読み取り専用で、DB やマイグレーショングラフには書き込みません。適用前に実行順序を確認するために使います。
データ変換があれば入力します(「プレースホルダーを入力する」を参照)。migration.ts を編集した場合はセルフエミットしてから、次を実行します。
pnpm prisma-next migrate --db $DATABASE_URL
migrate は確認を求めずに実行されます。破壊的操作の確認はここではなく db update にあります。適用する前に、プランの出力または migration show で破壊的操作を確認してください。
ワークフロー — プレースホルダーを入力する
概要:プランナーはデータ変換が必要であることは検出できますが、どのような変換を行うかは判断できません。型付きのひな形を作成して停止するため、変換を入力してからセルフエミットします。
Postgres
プランナーはデータ変換が必要であること(例:デフォルト値のない新しい NOT NULL カラムへのバックフィル)は検出できますが、どのような変換を行うかは判断できません。endContract を使って実際のクエリプランを作成し、check と run のクロージャーを入力します。
プランナーが出力するひな形は次のようになります。
// migrations/app/20260515T1200_add_user_name/migration.ts
import endContract from '../../snapshots/93f07d1b…c9e1e5a2/contract.json' with { type: 'json' };
import { Migration, MigrationCLI, addColumn, placeholder } from '@prisma-next/postgres/migration';
export default class M extends Migration {
override get operations() {
return [
addColumn('public', 'user', {
name: 'name',
typeSql: 'text',
defaultSql: '',
nullable: true,
}),
this.dataTransform(endContract, 'backfill user.name', {
check: () => placeholder('backfill user.name:check'),
run: () => placeholder('backfill user.name:run'),
}),
];
}
}
MigrationCLI.run(import.meta.url, M);
両方の placeholder(...) 呼び出しを、endContract から作成したクエリプランのクロージャーに置き換えます。check クロージャーは、行が存在すれば「未完了の作業がある」ことを示す行セットクエリを返す必要があります。一般的には <table>.select('id').where(<violation predicate>).limit(1) の形式です。スカラー/集計形式(count(*)、bool_and(...))ではコントラクトが暗黙に破られます。ランナーは check を2回ラップし(事前チェックでは EXISTS(...)、事後チェックでは NOT EXISTS(...))、常に1行を返すクエリでは EXISTS が常に true、NOT EXISTS が常に false になります。
ストレージハッシュが一致するよう、endContract に対してクエリビルダーを作成してください。別のコントラクト参照を使うと PN-MIG-2005 が発生します。入力後の形式(上に示したひな形で placeholder(...) 呼び出しを置き換えたもの。setNotNull などのファクトリーが追加で必要な場合は、2つ目の import を作成するのではなく、既存の @prisma-next/postgres/migration import 行に追加してください)。周辺の db セットアップについては prisma-next-queries を参照してください。
import endContract from '../../snapshots/93f07d1b…c9e1e5a2/contract.json' with { type: 'json' };
import { Migration, MigrationCLI, addColumn, setNotNull } from '@prisma-next/postgres/migration';
import { db } from './db'; // sql({ context: createExecutionContext({ contract: endContract, ... }) })
export default class M extends Migration {
override get operations() {
return [
addColumn('public', 'user', {
name: 'name',
typeSql: 'text',
defaultSql: '',
nullable: true,
}),
this.dataTransform(endContract, 'backfill user.name', {
check: () => db.users.select('id').where((f, fns) => fns.eq(f.name, null)).limit(1),
run: () => db.users.update({ name: '' }).where((f, fns) => fns.eq(f.name, null)),
}),
setNotNull('public', 'user', 'name'),
];
}
}
MigrationCLI.run(import.meta.url, M);
セルフエミットします。
node migrations/app/20260515T1200_add_user_name/migration.ts
セルフエミットすると ops.json が再生成され、migration.json の migrationHash が再計算されます。次回 migrate を実行すると、一貫性のあるパッケージが認識されます。
Mongo
Mongo の dataTransform 操作は、source / run が Mongo のクエリプラン形式(多くの場合、@prisma-next/mongo-query-ast/execution の RawAggregateCommand / RawUpdateManyCommand)を返す { check, run } オブジェクトを受け取ります。入力するまで、プランナーがそれらのソース内に placeholder(...) を残すことがあります。生成される migration.ts にはすべて、describe() の開始・終了部分(from / to コントラクトハッシュ)が含まれます。上記の Postgres の例では、簡潔にするため省略しています。ファクトリーは @prisma-next/target-mongo/migration からインポートします。
import { MigrationCLI } from '@prisma-next/cli/migration-cli';
import { Migration } from '@prisma-next/family-mongo/migration';
import { createIndex, dataTransform } from '@prisma-next/target-mongo/migration';
import { RawAggregateCommand, RawUpdateManyCommand } from '@prisma-next/mongo-query-ast/execution';
class M extends Migration {
override describe() {
return { from: '<hex>', to: '<hex>', labels: ['normalize-names'] };
}
override get operations() {
return [
createIndex('users', [{ field: 'name', direction: 1 }]),
dataTransform('lowercase-user-name', {
check: {
source: () => ({
collection: 'users',
command: new RawAggregateCommand('users', [
{ $match: { name: { $regex: '[A-Z]' } } },
{ $limit: 1 },
]),
meta: { target: 'mongo', storageHash: '…', lane: 'mongo-pipeline', paramDescriptors: [] },
}),
},
run: () => ({
collection: 'users',
command: new RawUpdateManyCommand(
'users',
{ name: { $exists: true } },
[{ $set: { name: { $toLower: '$name' } } }],
),
meta: { target: 'mongo', storageHash: '…', lane: 'mongo-raw', paramDescriptors: [] },
}),
}),
];
}
}
export default M;
MigrationCLI.run(import.meta.url, M);
同じ方法でセルフエミットします:node migrations/app/<dir>/migration.ts。
ワークフロー — 手動でマイグレーションを作成する
考え方:同じ形の Migration クラスを使えば、プランナーが計画できるものがない場合でも、操作を直接作成できます(カスタムデータ修正、拡張機能のインストール、ベースラインなど)。この場合も、ファイルを一から作成する必要はありません。migration new が空のパッケージを生成するので、その中の operations ゲッターを編集してから、自己出力します。
pnpm prisma-next migration new --name <snake_slug>
対象に応じて、フレームワークが生成したインポート行にファクトリー名を追加します(Postgres:@prisma-next/postgres/migration、Mongo:@prisma-next/target-mongo/migration)。--help と、レンダラーが出力したインポート一覧を確認してください。
Postgres のファクトリー(代表例):
- テーブル:
createTable、dropTable。 - カラム:
addColumn、dropColumn、alterColumnType、setNotNull、dropNotNull、setDefault、dropDefault。 - 制約:
addPrimaryKey、addForeignKey、addUnique、dropConstraint。 - インデックス:
createIndex、dropIndex。 - 列挙型:
createEnumType、addEnumValues、renameType、dropEnumType。 - 依存関係:
createSchema、createExtension、installExtension。 - 生の SQL を使うための手段:
rawSql({ id, label, operationClass, target, precheck, execute, postcheck, ... })。 - データ変換:
this.dataTransform(endContract, name, { check, run })(インスタンスメソッドであり、単独のファクトリーではありません)。
Mongo のファクトリー(@prisma-next/target-mongo/migration から):
- コレクション:
createCollection、dropCollection、validatedCollection、setValidation。 - インデックス:
createIndex、dropIndex。 - コレクションのオプション:
collMod。 - データ変換:
dataTransform(name, { check, run })(単独のファクトリーです。check/runは Mongo のクエリプラン形式を使用します)。
編集のたびに自己出力します(node migrations/app/<dir>/migration.ts)。
ワークフロー — ライブスキーマを確認する
考え方:db schema は読み取り専用で、ファイルに書き込むことはありません。デフォルトではライブスキーマをツリー形式で出力し、--json を指定すると JSON 形式で出力します。計画時や検証の一環として使用してください。
pnpm prisma-next db schema --db $DATABASE_URL
pnpm prisma-next db schema --db $DATABASE_URL --json > schema.json
組み込みのフィルターフラグはありません。1 つのテーブルだけが必要な場合は、JSON を jq(または好みの JSON ツール)にパイプしてください。
ワークフロー — コントラクトと DB を検証する(診断)
考え方:db verify は単独の診断コマンドです。通常の手順では、正常に完了した db update や migrate の後に実行するものではありません(これらのコマンドは、成功時にすでに検証を行い、マーカーを更新します)。ドリフトが疑われる場合や、DB がコントラクトに一致することを証明する必要がある場合に db verify を使用してください。
- Prisma Next の外部で手動 SQL を実行した場合や、場当たり的な編集を行った場合。
- バックアップからデータベースを復元した場合。
migrateが失敗した場合、または一部のみ適用された場合(特に Mongo では、DDL はトランザクションでラップされず、再開可能です)。PN-RUN-3002/PN-RUN-3001が実行時または別のコマンドから発生した場合。
モード:
- デフォルト — 完全な検証(スキーマ + マーカー)。
--marker-only— スキーマ検証を省略し、マーカーのみを確認します。--schema-only— マーカー検証を省略し、スキーマがコントラクトを満たしているかのみを確認します。--strictを追加すると、コントラクトにないスキーマ要素はエラーになります(デフォルトでは「DB に余分な要素があってもよい」とします)。
pnpm prisma-next db verify --db $DATABASE_URL
不一致がある場合、エラーエンベロープに失敗モード(PN-RUN-3002 のハッシュ不一致、PN-RUN-3001 のマーカー欠落、ターゲットの不一致、構造化パス付きのスキーマ問題)が示されます。
ワークフロー — マーカーに再署名する
考え方:db sign はマーカーを現在のコントラクトハッシュに書き換えます。DB が正とみなされ、マーカーが古くなっている手動修復の後に使用してください。db sign は最初にスキーマ検証を行い、スキーマがコントラクトと一致しない DB への署名を拒否します。そのため、署名が成功すれば、スキーマが一致し、マーカーも正しい状態になったことを意味します。
pnpm prisma-next db sign --db $DATABASE_URL
ワークフロー — ドリフトからの復旧
考え方:ドリフトとは、db verify によって、実際の DB スキーマがマーカーに記録された内容と一致しないことが報告される状態です。どちらが正しいかに応じて、適切な方法を選びます。
- コントラクトが正しく、DB が誤っている → マイグレーションを実行します。
db update(手早い方法。開発用 DB のみ)またはmigration plan+migrate(それ以外のすべて)を使います。 - DB が正しく、コントラクトまたはマーカーが誤っている → コントラクトを編集して DB に合わせます(
prisma-next-contractを参照)。emit を実行し、その後db signでマーカーを更新します。
どちらが正しいかを判定する診断方法:
pnpm prisma-next db schema --db $DATABASE_URL --json
pnpm prisma-next db verify --db $DATABASE_URL --json
db verify を使ってどちらが誤っているかを確認し、どちらかの方法を実行した後、診断結果なしで ok が返るまで再実行します。
ワークフロー — 部分的に適用されたマイグレーションからの復旧
考え方:Postgres では、各マイグレーションはトランザクション内で適用されます。途中で失敗するとロールバックされ、マーカーは前のマイグレーションの to ハッシュのままです。Mongo では、DDL は再開可能で、verify による確認を通過してからマーカーが進みます。db verify / db schema で診断し、失敗したパッケージの migration.ts を修正して、self-emit を実行し、migrate を再実行します。
部分的な状態が残る可能性がある失敗には、トランザクションラッパーの外で実行される Postgres の rawSql(...) ステップ、verify に失敗する前に部分的に適用された Mongo の DDL、外部への副作用(run クロージャーから他のシステムを呼び出す場合)があります。
診断:
pnpm prisma-next db verify --db $DATABASE_URL --json
pnpm prisma-next db schema --db $DATABASE_URL --json
修正して migrate を再実行します:
node migrations/app/<dir>/migration.ts
pnpm prisma-next migrate --db $DATABASE_URL
外部への副作用によって外部システムに中途半端な変更が残った場合は、再適用する前に手作業で修復します。
ワークフロー — MIGRATION.HASH_MISMATCH の解決
考え方:migrationHash はコンテンツアドレス方式です。不一致は、migration.json に保存されたハッシュが、ops.json(およびメタデータ)から再計算されたハッシュと一致しないことを意味します。原因はほとんどの場合、誰かが migration.ts を編集して self-emit を忘れたことです。該当するパッケージで self-emit を実行して解決します。
node migrations/app/<dir>/migration.ts
pnpm prisma-next migrate --db $DATABASE_URL
self-emit 自体が失敗する場合(たとえば、コントラクトが変更され、操作がマイグレーションの終了時点のコントラクトと整合しなくなった場合)、そのパッケージは古くなっています。バージョン管理から復元するか、削除して migration plan で再計画してください。
ワークフロー — 破壊的操作の確認プロンプトへの対応(db update のみ)
考え方:db update によって列やテーブルが削除される場合、適用前に停止して確認を求めます。このプロンプトは db update 固有のものです。migrate はプロンプトを表示せず、マイグレーションパッケージに含まれる処理をそのまま実行するため、migrate の前に計画を確認するか、migration show を呼び出してください。
db update が対話形式で破壊的操作を報告すると、警告に該当する操作が一覧表示されます。確認プロンプトは次のとおりです。
破壊的な変更を適用しますか?この操作は取り消せません。
対応方法:
- データが不要になっている場合は、「はい」と回答します。
- 「いいえ」と回答し、次のいずれかを行います。
migration planでマイグレーションの形を変更し、データを保持するようmigration.tsを手動編集します(例:新しい列にコピーしてから削除する)。- コントラクトの変更を元に戻して、破壊的操作を回避します。
非対話型の環境(CI、--no-interactive、--json)では、破壊的操作への応答は構造化エラーとして返されます。meta.destructiveOperations[] に削除される予定の項目が一覧表示されます。-y を付けて再実行し、自動承認するか、各操作に個別に対処してください。
よくある落とし穴
- 共有データベースや本番データベースに対して
db updateを使うこと。 絶対に避けてください。この変更ではマイグレーション履歴が残りません。migration planとmigrateを使ってください。 - データ変換を省略すること。
migration.tsにplaceholder(...)を残すと、次のmigrateでPN-MIG-2001が発生します。すべてのプレースホルダースロットを埋めて、必ずセルフエミットしてください。 ops.jsonを直接編集すること。 これは正規の成果物であり、編集元ではありません。migration.tsを編集してから、セルフエミットしてください。migration.tsの編集後にセルフエミットし忘れること。 次のmigrateは、コメントだけを追加した場合は古いops.jsonを使い、操作を変更した場合はMIGRATION.HASH_MISMATCHで失敗します。必ずセルフエミットしてください。db updateまたはmigrateの成功後に、定例でdb verifyを実行すること。 正常なフローでは冗長です。ドリフトの診断(手動編集、復元、migrateの失敗)に限ってdb verifyを使ってください。- Postgres の
this.dataTransformで集約を使ってcheckを終了すること。count(*)やbool_and(...)を返すと、事前チェックと事後チェックの契約に反し、両側が定数として解決されます。行セットの形式を使ってください:select('id').where(<violation>).limit(1)。 - 1 つのマイグレーションで 2 つの契約参照を使うこと。
this.dataTransform(endContract, ...)に渡すものとは異なる契約に対してクエリープランを構築すると、PN-MIG-2005が発生します。必ずモジュールスコープでendContractを一度だけインポートし、同じ参照を使ってください。 - Postgres で、名前変更をプランナーが検出すると期待すること。 Prisma Next には現在、契約内の名前変更を示すヒントがありません。プランナーは破壊的な削除と追加を出力します。
migration.tsを手動で編集し、破壊的な操作をALTER TABLE ... RENAME COLUMN ...を実行するrawSql({ ... })に書き換えてから、セルフエミットしてください(または、2 つのマイグレーションで保持/バックフィル/削除のパターンを使ってください)。prisma-next-contractの § フィールドの編集 — 名前変更 を参照してください。 - 空のファイルから
migration.tsを手書きする、またはレンダリング済みのインポート行を書き換えること。 マイグレーションファイルはフレームワークによってレンダリングされます。prisma-next migration plan(またはmigration new)にパッケージをレンダリングさせてから、フレームワークが残した編集箇所だけを変更してください。Postgres ではレンダリング済みの@prisma-next/postgres/migration(または@prisma-next/sqlite/migration)のインポートパスには手を加えず、Mongo ではレンダリングどおりの@prisma-next/family-mongo/migrationと@prisma-next/target-mongo/migrationを使ってください。新しいインポートパスを追加するのではなく、既存のファクトリーのインポート行にシンボルを追加してください。
Prisma Next がまだ対応していないこと
- 実行時のマイグレーション適用。 Prisma Next は、アプリの起動コードから保留中のマイグレーションを適用しません(サーバーレス/エッジ向けの「Drizzle パターン」)。回避策:アプリの起動前に、デプロイパイプラインから
prisma-next migrateを実行してください。実行時のマイグレーション適用機能を組み込みで必要とする場合は、prisma-next-feedbackスキルから機能リクエストを送ってください。 - ファーストクラスのシード機能。 Prisma Next には
prisma db seedに相当する機能がありません。回避策:dbインスタンスをインポートしてセットアップ用クエリーを実行する TypeScript スクリプトを作成し、package.jsonのスクリプトから呼び出してください。ファーストクラスのシード機能が必要な場合は、prisma-next-feedbackスキルから機能リクエストを送ってください。 - マイグレーションの圧縮。 Prisma Next は古いマイグレーションをベースラインに圧縮しません。マイグレーションは蓄積されます。履歴が非常に長い場合は、手動でベースラインを作成して古いものを削除する方法が選択肢になります。組み込みの圧縮機能が必要な場合は、
prisma-next-feedbackスキルから機能リクエストを送ってください。 - 契約内の名前変更ヒント。 プランナーは、フィールドの名前変更を削除と追加ではなく名前変更として検出できません。回避策:
migration.tsを手動で編集し、rawSql(...)でRENAME COLUMNを実行するか、2 つのマイグレーションにわたって保持/バックフィル/削除のパターンを使ってください。契約レベルの名前変更ヒントが必要な場合は、prisma-next-feedbackスキルから機能リクエストを送ってください。
グラフと履歴のコマンド
計画または適用の後、オフラインでマイグレーショングラフを確認できます。
pnpm prisma-next migration list— ディスク上のすべてのマイグレーションをグラフツリーとして表示します。--legend(記号の凡例を表示)、--ascii(パイプでも安全に使える記号)、--jsonに対応しています。pnpm prisma-next migration log --db $DATABASE_URL— 稼働中の DB から読み取った、適用済みマイグレーションの時系列順のフラットなテーブルです。--asciiと--jsonに対応しています。
グラフの完全なトポロジーを確認するには、pnpm prisma-next migration graph を実行します(--legend、--ascii、--dot、--json にも対応しています)。
@@control と DDL の対象範囲
@@control ポリシーによって Prisma Next の管理対象から除外されたオブジェクトは、計画される DDL から省かれます。ポリシーは次の 4 つです。managed(Prisma が DDL を計画して適用します)、tolerated(オブジェクトは存在してもかまいませんが、DDL は生成されません)、external(オブジェクトの存在が想定されますが、DDL は生成されません)、observed(Prisma は読み取りますが、書き込みは行いません)。スキーマで @@control(managed|tolerated|external|observed) を宣言してください。構文の作成方法については、prisma-next-contract と packages/2-sql/2-authoring/contract-psl/README.md を参照してください。
テレメトリー
CLI はデフォルトで匿名の使用状況データを収集します。オプトアウトするには、環境で PRISMA_NEXT_DISABLE_TELEMETRY=1 または DO_NOT_TRACK=1 を設定してください。オプトアウトの詳細については、docs/Telemetry.md を参照してください。
チェックリスト
- コントラクトが出力されている(
contract.jsonとcontract.d.tsが最新である)。 - 適切な手順を選択した。
db update(ローカル開発)か、migration plan+migrate(共有環境で使う場合)。 -
migration planの場合、migrateの前にmigration showを実行して内容を確認した。 -
migration.ts内のすべてのplaceholder(...)を埋め、endContractに対してビルドした(該当する場合)。 -
checkクロージャーがスカラー集計ではなく、行セットクエリである。 - TS の編集後に、自分で出力した(
node migrations/app/<dir>/migration.ts)。 -
migrate(またはdb update)を実行し、完了したことを確認した。 - ドリフトの診断時に限って
db verifyを使用した。適用後の定例手順としては使用していない。 - 共有データベースまたは本番データベースに対して
db updateを使用していない。 -
ops.jsonを直接編集していない。 -
meta.destructiveOperations[]を確認せずに、破壊的操作の確認プロンプトをスキップしていない。