Cloudflare PagesのEdge/Node.js混在エラー対処

Cloudflare PagesのEdge/Node.js混在エラー対処

※本記事にはプロモーション(広告・アフィリエイトリンク)を含みます。

Next.js App Router を @cloudflare/next-on-pages で Cloudflare Pages にデプロイしようとすると、ローカルの next dev では問題なく動いていたコードが、Module not found: Can't resolve 'fs' や The edge runtime does not support Node.js 'crypto' module でビルド・デプロイ時に止まることがあります。原因は共通していて、Cloudflare Pages の実行環境が V8 ベースの Edge Runtime であり、Node.js ではないことです。この記事では仕組みを整理したうえで、エラーの種類別に具体的な対処手順を示します。

なぜ Edge Runtime で Node.js モジュールが動かないか

Next.js の App Router はルートファイルごとにランタイムを宣言できます。

// app/api/example/route.ts
export const runtime = 'edge'; // または 'nodejs'(省略時はデプロイ先の設定に依存)

ローカルで next dev や next start を動かすときは、どちらの宣言でも Node.js プロセスの上で動作します。しかし @cloudflare/next-on-pages でビルドすると、すべてのルートが Cloudflare Workers(Edge Runtime)として変換されます。

Edge Runtime の V8 サンドボックスには Node.js のコア API が存在しないため、次のモジュールをそのまま使うとエラーになります。

カテゴリ 使えない代表例
ファイルシステム fs、child_process
ネットワーク低レイヤー net、tls、dgram
Node.js 組み込み暗号 crypto.createCipher など Node.js 固有の API
ORM のネイティブバイナリ Prisma の libquery-engine-* バイナリ

公式ドキュメント(@cloudflare/next-on-pages README、執筆時点)には「runtime = 'nodejs' を宣言したルートはサポートしない」と明記されています。

エラーメッセージと原因の対応表

ビルドやデプロイ時に出るエラーはメッセージから原因を絞り込めます。

エラー文(抜粋) 主な原因
Module not found: Can't resolve 'fs' fs を import するモジュールが含まれている
The edge runtime does not support Node.js 'crypto' module Web Crypto API でカバーされていない crypto 操作
Route /xxx uses a Node.js runtime which is not supported export const runtime = 'nodejs' が残っている
Dynamic Code Evaluation … not allowed in Edge Runtime eval() や new Function() を使うライブラリ
PrismaClientInitializationError / エンジンバイナリ関連 Prisma の SQLite ドライバーが Edge 非対応

まず npx @cloudflare/next-on-pages をローカルで実行し、ビルドエラーを手元で再現してください。Cloudflare Pages のダッシュボードにしかエラーが出ないように見えても、ローカルビルドで先に確認できます。

対処1:nodejs_compat フラグを有効にする

buffer、events、path、stream、util、string_decoder、url、querystring、crypto(一部)などは、Cloudflare Workers の互換フラグ nodejs_compat を有効にすると polyfill されます。対応モジュールの一覧は Cloudflare 公式ドキュメントの「Workers Node.js compatibility」ページに記載されています(執筆時点)。

Cloudflare Pages ダッシュボードで設定する手順

  1. プロジェクトの Settings → Functions を開く
  2. Compatibility flags の入力欄に nodejs_compat を入力
  3. Production と Preview の両方に追加して保存
  4. 再デプロイを実行する

ローカルプレビューで設定する場合(wrangler.toml)

name = "my-next-app"
compatibility_date = "2024-09-23"
compatibility_flags = ["nodejs_compat"]

fs や child_process などファイルシステム・プロセス系は polyfill の対象外です。このフラグで解消しないエラーは次の対処に進んでください。

対処2:Node.js 依存の import を切り離す

fs など Edge 非対応モジュールがルートや Server Component に混入しているとき、そのコードパスを Edge から排除します。

自分のコードに fs の import がある場合

該当コードを削除し、ファイル操作が必要なら Cloudflare R2 などの Edge 対応ストレージに置き換えます。

ライブラリの内部で require('fs') されている場合

ライブラリを Edge 対応の代替品に換えるか、そのライブラリを呼ぶ処理を Cloudflare Pages 外の Node.js エンドポイントに委譲する設計変更が必要です。

また、runtime = 'nodejs' を宣言したルートが1つでも残っていると @cloudflare/next-on-pages のビルドが失敗します。プロジェクト全体を検索して削除してください。

# nodejs runtime の宣言が残っていないか確認
grep -r "runtime = 'nodejs'" app/

対処3:Prisma(SQLite)が原因のとき

Prisma の SQLite ドライバーはネイティブバイナリを使うため、Edge Runtime では動きません。

選択肢 概要 注意点
Cloudflare D1 + prisma-adapter-d1 Cloudflare のマネージド SQLite。Prisma の構文を維持できる マイグレーション手順が変わる
Drizzle ORM + Cloudflare D1 Edge ネイティブ設計。バンドルが軽い Prisma とのスキーマ互換なし
自前 Node.js サーバーに委譲 Prisma + SQLite をそのまま使い続けられる Cloudflare Pages とは別にホストが必要

筆者の自作ECサイトでは Prisma + SQLite の構成を自宅の Linux サーバー(systemd 常駐・Cloudflare Tunnel 経由)で動かしており、Cloudflare Pages にはデプロイしていません。Cloudflare Pages へ移す必要が生じた場合は prisma-adapter-d1 への切り替えが現実的な経路だと考えています。

Edge Runtime の制約が根本にある問題は他にもあります。revalidate が Cloudflare Pages で動かない理由 や middleware の cookie が Cloudflare Pages で動かない原因 も、同じ実行環境の違いから来ているため、あわせて確認しておくと対応が速くなります。

まとめ

  • @cloudflare/next-on-pages はすべてのルートを Edge Worker に変換するため、runtime = 'nodejs' は使えない
  • buffer・crypto(一部)などは nodejs_compat フラグの追加で解決できる
  • fs・child_process・Prisma SQLite バイナリは polyfill の対象外。ライブラリの換装か設計変更が必要
  • ローカルで npx @cloudflare/next-on-pages を実行してエラーを再現させてから対処するのが効率的なアプローチです

次のアクション:ターミナルで npx @cloudflare/next-on-pages && wrangler pages dev .vercel/output/static を実行し、本番と同じ Edge 環境でエラーを再現させてから原因を特定してください。ダッシュボードのビルドログを読むより手元で先に確認するほうが効率的と考えられます。

よくある質問

@cloudflare/next-on-pagesでexport const runtime = 'nodejs'を使えますか?

使えません。同アダプターはすべてのルートを Edge Runtime(Cloudflare Workers)として変換するため、nodejs ランタイムを宣言したルートはビルドエラーになります(執筆時点)。

nodejs_compatフラグを設定したのにまだfsのエラーが出ます。なぜですか?

`nodejs_compat` が polyfill するのは `buffer`・`events`・`stream` など一部のモジュールで、`fs` は対象外です。`fs` を使うコードやライブラリは Edge 対応の代替品に換えるか、処理を Node.js 環境のエンドポイントに委譲する設計変更が必要です。

ローカルのnext devでは動くのにCloudflare Pagesだけ失敗するのはなぜですか?

`next dev` は Node.js プロセス上で動くため Node.js API が使えますが、Cloudflare Pages では `@cloudflare/next-on-pages` がすべてのルートを V8 ベースの Edge Worker に変換します。実行環境が根本的に異なるため、ローカルで動いてもデプロイ後に失敗することがあります。