メインコンテンツへスキップ

VillageSQL is a drop-in replacement for MySQL with extensions.

All examples on this page work on VillageSQL. Install Now →
Prisma は最も広く使われている TypeScript ORM の 1 つであり、Next.js の App Router は新しいプロジェクトがデータベースに到達する一般的な方法です。このガイドでは、Prisma 7 を通じて MySQL の行を一覧表示し作成する小さな Next.js アプリを構築し、古い Prisma のチュートリアルから変わった部分を扱います。接続 URL はスキーマファイルの外へ移動し、ドライバーアダプターはもはや任意ではありません。VillageSQL は MySQL のドロップイン代替なので、ここにあるすべてのコマンドは変更なしで VillageSQL に対して動作します。

データベースの作成

Prisma には 2 つのデータベースが必要です。アプリが使うものと、マイグレーションの計算のために内部で使う 2 つ目の「シャドウ」データベースです。両方と、それぞれに権限を持つ専用のユーザーを作成します。
シャドウデータベースは存在しさえすればよく、Prisma がその中にテーブルを自動的に作成し削除します。Prisma 自身がシャドウデータベースを作成できるように *.* に対してより広い CREATE/DROP 権限を付与するのではなく、前もって作成してアプリユーザーにその 1 つのデータベースへの権限を付与しておくと、パスワードが漏洩した場合の影響範囲をサーバー全体ではなく 2 つのデータベースに抑えられます。

アプリのスキャフォールド

メジャーバージョンを固定してください。執筆時点で、prisma の npm の latest タグは 8.0 のリリース候補を指しています。試す分には問題ありませんが、動作し続けることを目的としたガイドのデフォルトとしては適切ではありません。

Prisma の初期化

prisma init はデフォルトで postinstall ステップを実行し、Claude Code、Cursor、Windsurf のエージェントスキルをリポジトリにスキャフォールドします (.claude/、.windsurf/、.agents/、および skills-lock.json)。--no-skills はこれをスキップします。Prisma と並行して AI コーディングエージェントを使っているなら本当に役立つ機能ですが、このガイドの範囲外です。 これにより prisma/schema.prisma、.env ファイル、および prisma7.config.ts が作成されます (Prisma 7 では設定ファイル名にバージョンのサフィックスが付きます)。接続文字列を設定します。
.env
古い Prisma のチュートリアルは、データソースの URL を schema.prisma に直接置いていました。Prisma 7 では、シャドウデータベースの URL を含む接続 URL は、スキーマファイルではなく prisma7.config.ts にあります。
prisma7.config.ts
schema.prisma は prisma init が作成した generator ブロックを保持し、今ではデータソースにプロバイダーのみを宣言して、接続 URL は持ちません。
prisma/schema.prisma

マイグレーションの実行

これはスキーマを適用し、prisma/migrations/<timestamp>_init/migration.sql を生成し、prisma generate を自動で呼び出します。テーブルが存在することを確認します。

ドライバーアダプターで接続する

Prisma 7 の生成されたクライアントは、もはや自力では接続しません。引数なしの new PrismaClient() は今では型チェックに失敗します。データベースごとに 1 つのパッケージであるドライバーアダプターを渡します。
@prisma/adapter-mariadb は MariaDB と MySQL の両方のためのアダプターです。ワイヤプロトコルが共通なので、素の MySQL に対して動作するのと同じように VillageSQL に対しても動作します。Next.js の開発モードのホットリロードがファイルを保存するたびに新しいコネクションプールを開かないように、シングルトンを設定します。
src/lib/prisma.ts

新しいアカウントへの最初の接続

MySQL 8 と VillageSQL は caching_sha2_password プラグインでアカウントを作成します。あるアカウントが初めて認証するとき、クライアントは RSA 鍵交換を完了しなければなりません。その後はサーバーが結果をキャッシュし、以降の接続はそれをスキップする高速なパスを取ります。@prisma/adapter-mariadb は暗号化されていない接続でのその交換を拒否するため、このアカウントを一度も認証したことのないサーバーでは、ビルドが失敗します。
このメッセージには認証に関する言及がなく、active=0 idle=0 はサーバーに到達できないかのように読めます。背後のドライバーのエラーのほうがより具体的です。
ローカル開発では、接続 URL にオプションを追加します。
.env
暗号化されていない接続で鍵を取得すると、その最初のハンドシェイクを傍受できる誰にでもパスワードがさらされるため、ローカルサーバー以外に対しては、このオプションではなく TLS を使ってください。 これは FastAPI のガイドが asyncmy について記録しているのと同じ罠であり、同じ理由で断続的に起きます。mysql CLI を含め、どれかのクライアントがそのアカウントの完全な認証を一度完了すると、FLUSH PRIVILEGES またはサーバーの再起動でキャッシュがクリアされるまで、キャッシュされた結果が問題を隠します。 生成されたクライアントのインポートパスには 2 つの癖があります。index.ts がないため、@/generated/prisma (ディレクトリ) ではなく @/generated/prisma/client (ファイル) をインポートします。また、そのファイル内のすべてのエクスポートは @ts-nocheck で型付けされています。読むためではなくインポートするための生成コードだからです。

Server Component からの読み書き

src/app/page.tsx
prisma.post.findMany() は Server Component として実行されるため、一覧はクライアント側のフェッチなしに、データがすでに HTML に含まれた状態でレンダリングされます。フォームは Server Action ("use server") に送信され、同じ Prisma クライアントを通じて書き込み、revalidatePath("/") を呼び出すことで、クライアント側の更新なしに新しい投稿が表示されます。 この時点で npm run build を実行すると、実際にデータベースにクエリが発行されます。ホームページは動的 API を使っていないため、Next.js はビルド時にそれを静的コンテンツとしてプリレンダリングします。つまり findMany() はリクエスト時だけでなくビルド中にも実行されます。npm run build 中にデータベースに到達できなければ、ビルドはそこで失敗します。したがって、このアプリの CI パイプラインには、実行時だけでなくビルド時にも到達可能なデータベースが必要です。

よくある質問

本番環境でもシャドウデータベースは必要ですか?

いいえ。prisma migrate dev は開発中にスキーマの差分を検出するためにこれを使います。本番環境では prisma migrate deploy を使ってください。これは既存のマイグレーションファイルを、シャドウデータベースにまったく触れずに適用します。

なぜ独立したスクリプトが “Cannot read properties of undefined (reading ‘prepareCacheLength’)” で失敗するのですか?

そのスクリプトの環境では process.env.DATABASE_URL が undefined です。Next.js は next dev と next build のために .env を自動的に読み込みますが、素の node や tsx のスクリプトは読み込みません。スクリプトの先頭に import "dotenv/config" を追加してください。

代わりに @prisma/adapter-pg の MySQL 版を使えますか?

MySQL 固有のアダプター名はありません。@prisma/adapter-mariadb が、Prisma が MariaDB と MySQL の両方 (VillageSQL を含む) のために提供しているものです。

トラブルシューティング

関連項目