本文へ移動
hanzochang

技術と実践のノート

mastra x prisma ビルドエラー - production buildでprisma generateでclientを生成できない問題の解消

公開

著者:株式会社hanzochang

mastraにprismaを組み合わせて本番ビルドを行う際に、prismaのclientがbuildできない問題。ESMとCommonJSの互換性問題が原因で発生するこの問題の解決方法を詳しく解説します。

はじめに

この記事は、mastraにprismaを組み合わせて本番ビルドを行う際に発生する、prismaのclientがbuildできない問題について解説します。

実際にmastraでアプリケーションを開発していて、ローカルでは問題なく動作するが、本番環境でビルドしようとするとgenerateできているはずのprisma clientが参照できないという問題に当たりました。

背景として、MastraではPostgreSQLを使ったデータベース操作が推奨されており、公式ドキュメントでも@mastra/pgパッケージを使用したPostgreSQLストレージの実装が提供されています(出典:Mastra Storage Documentation)。しかし、Prismaはクエリビルダとマイグレーション管理が楽なので、今回はPrismaを直接使用することにしました。

目次

対象読者

  • mastraにprismaを組み合わせて本番ビルドを行いたい方
  • prismaのclientがbuildできずに困っている方
  • ESMとCommonJSの互換性問題に悩んでいる方

対象バージョン

text
- "@mastra/core": "^0.10.12"
- "mastra": "^0.10.12"
- "@prisma/client": "^6.11.1",
- "prisma": "^6.11.1"
text
- "@mastra/core": "^0.10.12"
- "mastra": "^0.10.12"
- "@prisma/client": "^6.11.1",
- "prisma": "^6.11.1"

主要エラーメッセージ

text
The requested module '@prisma/client' is a CommonJS module,
which may not support all module.exports as named exports.
text
The requested module '@prisma/client' is a CommonJS module,
which may not support all module.exports as named exports.

prisma generateをビルドプロセスで行っているはずなのに、なぜか生成されない。。調べてみるとESMとCommonJSの互換性問題が原因。

結論

MastraとPrismaを組み合わせた本番ビルドでは、ESMとCommonJSの互換性問題により、PrismaClientのインポートが失敗してしまいます。

Mastraのバンドリングプロセスが標準的なESMインポート文を正しく処理できないことが原因でした。Prismaスキーマの設定最適化、ESM互換のインポート方法の実装、Mastra用のprisma clientビルドプロセスの構築が必要です。

主な原因:

1. ESMとCommonJSの互換性問題

  • MastraはESMでビルドされる:MastraはTypeScriptフレームワークとして、ESM(ES Modules)形式でビルドされます(出典:Mastra公式ドキュメント
  • PrismaはデフォルトでCommonJSで生成される:Prisma v6.11.1では、デフォルトのprisma-client-jsジェネレーターはCommonJSでクライアントを生成します(出典:Prisma公式ドキュメント
  • 結果:この2つのモジュールシステムの違いにより、インポート時に互換性エラーが発生
2. MastraでのPrismaクライアントビルド問題
  • Mastraのビルド環境でのPrismaクライアント不整合:Mastraが.mastra/outputディレクトリにビルドする際、元のPrismaクライアントが正しく参照されない問題が発生します
  • 結果:ビルド後の実行環境でPrismaクライアントが正常に動作しない

対処方法

問題を解決するために、以下の手順で対処していきます:

  1. Prismaスキーマの設定を最適化する
  2. Prismaクライアントを最新版に更新する
  3. ESM互換のインポート方法を実装する
  4. ビルドプロセスを改善する

それぞれ詳しく見ていきましょう。

解決方法具体

1. Prismaスキーマの設定最適化

まず、prisma/schema.prismaのgeneratorセクションを以下のように修正します:

prisma
generator client {
  provider   = "prisma-client-js"
  engineType = "binary"
}
prisma
generator client {
  provider   = "prisma-client-js"
  engineType = "binary"
}
重要なポイント:
  • engineType = "binary"でESM互換に

2. Prismaクライアントのバージョン更新

次に、Prismaクライアントを最新版に更新:

bash
pnpm update @prisma/client@^6.11.1
pnpm run prisma:generate
bash
pnpm update @prisma/client@^6.11.1
pnpm run prisma:generate

最新版のPrismaクライアントはESM互換性が大幅に改善されているので、この更新だけでも問題が解決する場合があります。

3. ESM互換のインポート方法の実装

通常、PrismaClientを使用する際は、何も意識せずに以下のようにインポートしてしまいます:

typescript
import { PrismaClient } from '@prisma/client'
typescript
import { PrismaClient } from '@prisma/client'

しかし、Mastraの本番ビルドにおいては、この書き方がESMとCommonJSの互換性問題を引き起こします。

ビルドにおいては、以下の書き方にする必要があります:
typescript
import pkg from '@prisma/client'
const { PrismaClient } = pkg
typescript
import pkg from '@prisma/client'
const { PrismaClient } = pkg
なぜこの書き方が必要なのか:
  • 通常の書き方:named importを使用(import { PrismaClient }
  • ESM互換の書き方:default importを使用してから分割代入(import pkg
  • Mastraのビルドプロセスでは、default importの方が確実にCommonJSモジュールと互換性を保てる

4. ビルドプロセスの改善

なぜこんな複雑なビルドプロセスが必要なのか:

通常のNode.jsアプリケーションであれば、prisma generateを一度実行すれば済む話ですが、Mastraの場合は以下の特殊な事情があります:

  1. Mastraは独自のビルドディレクトリを使用mastra buildコマンドで.mastra/outputディレクトリにビルド結果を出力
  2. Prismaクライアントのパス解決問題:ビルド後の環境では、元のPrismaクライアントへのパスが正しく解決されない
  3. ビルド環境とランタイム環境の分離:ビルド時とランタイム時で異なる環境になるため、両方でPrismaクライアントが必要

これらの問題を解決するために、package.jsonのbuildスクリプトを以下のように修正します:

json
{
  "scripts": {
    "build": "mastra build && cp -r prisma .mastra/output/ && \\
             cd .mastra/output && \\
             pnpm install prisma@^6.11.1 && \\
             pnpm exec prisma generate"
  }
}
json
{
  "scripts": {
    "build": "mastra build && cp -r prisma .mastra/output/ && \\
             cd .mastra/output && \\
             pnpm install prisma@^6.11.1 && \\
             pnpm exec prisma generate"
  }
}
このスクリプトの処理内容:
  1. Mastraアプリケーションをビルド:通常のMastraビルドプロセス
  2. Prismaディレクトリを出力先にコピー:ビルド後の環境でもスキーマファイルが参照できるように
  3. 出力先でPrismaクライアントを生成:ランタイム環境で正しく動作するように
なぜビルド後にPrisma generateが必要なのか:

Mastraは独自のビルドシステムにより、.mastra/outputディレクトリでビルド結果を実行します。そのため、この場所でPrismaクライアントを生成する必要があります。

  • Mastraのランタイム環境.mastra/outputディレクトリが実際の実行環境
  • Prismaクライアントの参照:この環境でPrismaクライアントが正しく動作するよう生成が必要

この煩雑なプロセスは、Mastraの独自ビルドシステムとPrismaクライアントの生成タイミングの不整合から生じる問題を解決するための必要な措置です。

他TIPS

Docker環境でのバイナリ互換性エラー

Docker環境(特にAlpine Linux)でバイナリ互換性エラーが発生した場合は、schema.prismaに以下を追加します:

prisma
// schema.prismaに追加
generator client {
  binaryTargets = ["native", "linux-musl-openssl-3.0.x"]
}
prisma
// schema.prismaに追加
generator client {
  binaryTargets = ["native", "linux-musl-openssl-3.0.x"]
}

まとめ

MastraとPrismaを組み合わせた本番ビルドで発生するこの問題は、実際に遭遇してみると結構厄介な問題でした。

この問題は2つの大きな要因で発生します:

1. ESMとCommonJSの互換性問題
  • MastraがESMでビルドされる一方、PrismaがデフォルトでCommonJSで生成される
  • 異なるモジュールシステム間でのインポート処理の違いによりエラーが発生

2. MastraでのPrismaクライアントビルド問題

  • Mastraの独自ビルドシステム(.mastra/outputディレクトリ)での実行
  • ビルド後の環境でPrismaクライアントが正しく参照されない問題
解決のポイント:
  1. ESM互換のインポート方法import pkg from "@prisma/client"を使用
  2. 適切なビルドプロセス.mastra/outputディレクトリでのPrismaクライアント生成
  3. Prismaスキーマの最適化engineType = "binary"でESM互換性を向上
参考情報:

最初は何が原因かわからずに困ってしまいましたが、この記事で紹介した解決方法を段階的に実装することで、安定したMastraアプリケーションを構築できるようになりました。

同じような問題に遭遇している方の参考になれば幸いです。

この記事を書いた人

Webプランナー、開発会社の創業メンバーを経て、Fintech・DX・Web3の企画・開発に従事。2021年に独立し、2023年に株式会社hanzochangを設立。現在はAIを活用した業務改善と、自社サービス「指定管理者制度AI」の開発・運用に取り組んでいます。

半澤勇大のXアカウント(新しいタブで開く)

この記事の株式会社hanzochangについて
少し紹介させてください!

この記事に関連する当社のサービス

AIエージェント開発

人の代わりに仕事を進めるAIを、御社の業務にも。

情報収集、原稿や画像の作成、システムへの入力など、複数の作業を実行するAIエージェントを開発します。人が確認する工程も含めて設計し、本番運用まで支援します。

サービスの詳細を見る
メガネをかけたJくんが座禅を組み、背後に多数の手描きワークフローが広がるイラスト。
  • 担当する仕事を設計

    AIに任せる作業と、人が判断する条件を整理。

  • 資料・システムと連携

    社内データやAPIにつなぎ、一連の作業を実装。

  • 評価・本番運用

    出力の精度と実行結果を確かめ、継続的に改善。

業務改善・AI活用について、お気軽にご相談ください。