🫥

運用中のDBに後付け Prisma Migrate を途中から導入する実践ガイド

に公開2

運用中のDBに後付け Prisma Migrate を途中から導入する実践ガイド(ハマりどころ解説付き)

はじめに (きっかけ)

「このプロジェクト、最初は Prisma 使ってたけど、マイグレーションまでは管理してなかったんだよな...」
「開発も進んで、そろそろちゃんとスキーマ変更を管理したいけど、_prisma_migrations テーブルがない...」

そんな状況、ありませんか? 私もまさにその状況に直面しました。Prisma は導入済みでデータベーススキーマも存在しているけれど、Prisma Migrate によるマイグレーション管理は行われていない。運用が始まっているシステムだと、気軽に db push するわけにもいきません。

この記事では、そんな状況から Prisma Migrate を後付けで導入しようとして、実際に私が経験した試行錯誤やハマりどころを踏まえつつ、具体的な手順と注意点を解説します。

前提条件

この記事は、以下の状況を想定しています。

  • Node.js と npm/yarn/pnpm がインストールされている。
  • プロジェクトに Prisma CLI と Prisma Client が導入済み。(Prisma 3 以降を想定)
  • マイグレーション管理されていない既存のデータベースとスキーマが存在する。
  • 最終的に prisma migrate devprisma migrate deploy を使ってスキーマ変更を管理したい。

準備: 超重要! schema.prisma の整備と配置場所

途中から Prisma Migrate を導入する上で、最も重要と言っても過言ではないのが、schema.prisma ファイルの準備とその配置場所です。

結論から言うと、schema.prisma はプロジェクトルート直下の prisma ディレクトリに配置してください。 これが Prisma の標準的な規約であり、後述する多くのトラブルを回避する鍵になります。

具体的な手順は以下の通りです。

  1. prisma ディレクトリの作成:
    プロジェクトルートに prisma ディレクトリがなければ作成します。

    mkdir prisma
    
  2. schema.prisma の移動:
    もし schema.prisma がプロジェクトルートなど、prisma ディレクトリ以外の場所にある場合は、prisma ディレクトリの中に移動させます。

    # 例: ルートにある schema.prisma を移動する場合
    mv schema.prisma prisma/
    
  3. schema.prisma と DB スキーマの同期:
    prisma/schema.prisma の内容を、現在のデータベーススキーマの構造と一致させる必要があります。これには主に2つの方法があります。

    • prisma db pull を使う (推奨):
      現在のデータベーススキーマを元に schema.prisma を自動生成(または上書き)します。これが最も簡単で確実です。

      npx prisma db pull
      

      注意: このコマンドは prisma/schema.prisma をデータベースの内容で完全に上書きします。手動で追記したコメントやカスタム設定などがある場合は、実行前にバックアップを取るか、実行後に再度追記してください。

    • 手動で編集する:
      既存の prisma/schema.prisma を直接編集し、現在のデータベーススキーマと完全に一致するように修正します。テーブル定義、カラム定義、リレーションなどを正確に記述する必要があります。

これで、Prisma Migrate を導入する準備が整いました。prisma/schema.prisma が最新のDB状態を反映しているはずです。

導入方法: ベースラインの設定 (resolve --applied を使用)

Prisma 3 以降では、既存のデータベーススキーマを Prisma Migrate の管理下に置く(ベースラインを設定する)ために prisma migrate resolve コマンドを使用します。

(注記) Prisma 2.x 系には prisma migrate baseline という専用コマンドがありましたが、Prisma 3 以降では非推奨となり、resolve コマンドに機能が統合されました。

手順:

  1. ベースライン用マイグレーションディレクトリ作成:
    最初のマイグレーションファイル(実際には空のスキーマからの差分を記録するもの)を格納するディレクトリを作成します。名前は公式ドキュメントに合わせて 0_init とするか、混乱を避けるためにタイムスタンプ付きの名前にしても良いでしょう(例: 20250407000000_init)。ここでは 0_init を使います。

    mkdir -p prisma/migrations/0_init
    
  2. (任意だが推奨) 空スキーマからの差分 SQL 生成 (記録用):
    現在の schema.prisma の状態を表現する SQL を生成し、migration.sql として保存します。これは実際にデータベースに適用するためのものではなく、あくまで「この状態がベースラインである」という記録のためです。

    npx prisma migrate diff --from-empty --to-schema-datamodel prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
    

    注意: 必ず --from-empty を付け、--to-schema-datamodel で正しい prisma/schema.prisma のパスを指定してください。

  3. マイグレーションを「適用済み」としてマーク:
    作成した 0_init マイグレーションが、あたかも既にデータベースに適用されたかのように Prisma に認識させるため、以下のコマンドを実行します。

    npx prisma migrate resolve --applied 0_init
    

    これにより、_prisma_migrations テーブルが(なければ)作成され、0_init が適用済みとして記録されます。

これで、既存のデータベーススキーマが Prisma Migrate の管理下に置かれました。

ハマりどころとトラブルシューティング

さて、ここからは私が実際にハマった点や、その解決策について共有します。これらの多くは schema.prisma の配置場所が原因でした。

1. schema.prisma の場所が prisma/ ディレクトリじゃない場合

最初に試したとき、schema.prisma をプロジェクトルートに置いたまま進めようとして、以下の問題に遭遇しました。

  • prisma migrate diff でのエラー:
    --to-schema-datamodel ./schema.prisma のように指定しても、Error: Could not load ... file or directory not found というエラーが発生しました。これは Prisma CLI が規約通り prisma/schema.prisma を期待しているためと考えられます。prisma/ ディレクトリに移動し、パスを prisma/schema.prisma に修正することで解決しました。

  • prisma migrate resolve での P3017 エラー:
    schema.prisma をルートに置いたまま、--schema ./schema.prisma オプションを使って resolve を試みたところ、以下のエラーが発生しました。

    $ npx prisma migrate resolve --schema ./schema.prisma --applied 0_init
    Environment variables loaded from .env
    Prisma schema loaded from schema.prisma # スキーマは読み込めているが...
    Datasource "db": PostgreSQL database "geake", schema "public" at "localhost:5432"
    Error: P3017 # ↓ エラー発生!
    
    The migration 0_init could not be found. ...
    

    --schema オプションでスキーマファイルの場所は指定できているにも関わらず、resolve コマンドが prisma/migrations/0_init ディレクトリを見つけられないという状況でした。

    原因の推測と結論: Prisma CLI は、たとえ --schema でスキーマの場所を指定されても、マイグレーションディレクトリの探索など、内部的な処理において prisma/ ディレクトリ構造という**「規約」**に強く依存している可能性が高いです。標準的でない場所に schema.prisma があると、この規約から外れるため、0_init のようなマイグレーション名を正しく解決できないようです。
    対策はただ一つ、schema.prismaprisma/ ディレクトリに置くしかないっぽい😇

2. prisma migrate resolve での P3017 エラー (再訪)

schema.prisma の場所が適切でも、P3017 エラーが出る可能性はあります。

  • マイグレーション名の指定ミス: --applied に指定する名前は、prisma/migrations ディレクトリ内に実際に存在するディレクトリ名と完全に一致させる必要があります。ls prisma/migrations で確認し、0_init なのか、あるいは <timestamp>_<name> 形式の名前なのかを正確に指定してください。
    # ls prisma/migrations で確認した名前を指定する
    npx prisma migrate resolve --applied <実際のディレクトリ名>
    
  • 0_init の扱い: 私の経験では、schema.prismaprisma/ ディレクトリにあればresolve --applied 0_init は問題なく動作しました。しかし、--schema オプションを使った場合は失敗した経緯もあり、ツールの挙動がパスの状況によって変わる可能性は否定できません。規約に従うのが最も安全です。

導入後の確認

resolve コマンドが成功したら、以下の点を確認しましょう。

  1. _prisma_migrations テーブルの存在: データベース内にこのテーブルが作成されているか確認します。
    -- 例: PostgreSQL の場合
    \dt _prisma_migrations;
    SELECT * FROM _prisma_migrations;
    
    1. prisma migrate status コマンド: このコマンドで、Prisma がデータベースのマイグレーション状態をどのように認識しているか確認できます。ベースライン (0_init など) が適用済み (Applied) になっていれば OK です。
    npx prisma migrate status
    

    今後の運用

これで、Prisma Migrate の管理下にデータベースを置くことができました! 今後は以下のように運用できます。

  • スキーマ変更: prisma/schema.prisma を編集します。
  • マイグレーション作成と開発 DB への適用: npx prisma migrate dev --name <migration_description> を実行します。
  • 本番環境などへの適用: npx prisma migrate deploy を実行します。

まとめ

運用中のシステムに後から Prisma Migrate を導入するのは、いくつかのポイントを押さえれば十分に可能です。

  • prisma migrate resolve --applied <baseline_migration_name> を使ってベースラインを設定するのが現在の標準的な方法です。
  • 最重要: schema.prisma は必ず prisma/ ディレクトリに配置する! これだけで多くの問題を回避できます。
  • resolve コマンドで指定するマイグレーション名は、実際に存在するディレクトリ名と一致させる。
  • ハマりどころを知っておけば、スムーズに導入を進められます。

この記事が、同じような状況で困っている方の助けになれば幸いです。

参考資料

Discussion

omihirofumiomihirofumi

https://www.prisma.io/docs/orm/prisma-schema/overview/location

The location specified by the --schema flag, which is available when you introspect, generate, migrate, and studio:

resolveは上記に該当しないので、機能してないのかもしれないです🤔

resolveのリファレンスには--schemaありますけど、、😅
https://www.prisma.io/docs/orm/reference/prisma-cli-reference#migrate-resolve

abimaru XDabimaru XD

本当ですね・・・。
完全に罠と化してる状態かもです。
それか、0_initみたいなフォルダ名のときだけとか?なのかなって今更思ったりしました。