Next.js を Cloudflare で動かすときのつまずき 10 選 — 2026 年の現行パス

Cloudflare 上で Next.js を動かす公式推奨パスは 2024 年後半に大きく変わりました。現行は @opennextjs/cloudflare + Cloudflare Workers、@cloudflare/next-on-pages + Pages は legacy 扱いです。本記事では Next.js 16 系を Cloudflare Workers に載せるときにハマるポイントを、原因と回避策つきで 10 項目まとめます。

「Next.js を Cloudflare で動かす」は、2024 年後半に公式推奨パスが Pages から Workers へ移りました。2026-04 時点の正解は、Next.js 16 + @opennextjs/cloudflare adapter + Cloudflare Workers で、旧来の @cloudflare/next-on-pages + Pages は legacy 扱いです。本記事では現行パスを前提に、実際に詰まる 10 箇所を整理します。

到達点と前提

  • Next.js 16(16.2 系)/ App Router 前提
  • @opennextjs/cloudflare v1.19
  • Cloudflare Workers にデプロイ(Pages ではなく)
  • nodejs_compat フラグ有効、compatibility_date: "2024-09-23" 以降

1. デプロイ先の選び間違い(Workers か Pages か)

新規 Next.js プロジェクトは Workers + @opennextjs/cloudflare が推奨です。Pages で動かす @cloudflare/next-on-pages は引き続き動きますが、新機能(Server Actions 最適化 / Node API サポートの拡充 / assets binding 系)は Workers 側に集まっています。Pages → Workers 移行削除せず新 Workers アプリで並行公開 → 切替が事故が少ないです。

2. 古い @cloudflare/next-on-pages を選んでしまう

社内テンプレや古いブログ記事をコピーすると、@cloudflare/next-on-pages が入ります。@cloudflare/next-on-pages は 2025-09 に GitHub リポジトリがアーカイブされ、公式に deprecated 済みです。package.json の devDep に @cloudflare/next-on-pages があり、npx @cloudflare/next-on-pages でビルドしているなら、@opennextjs/cloudflare への移行を先に検討してください。

3. nodejs_compat フラグ忘れ

@opennextjs/cloudflare は Node 互換 API に依存します。wrangler.jsoncnodejs_compat を入れ忘れると、crypto / buffer / util 等を触るサーバーコードが実行時に ReferenceError で落ちます。

{
  "main": ".open-next/worker.js",
  "compatibility_date": "2024-09-23",
  "compatibility_flags": ["nodejs_compat"],
  "assets": {
    "directory": ".open-next/assets",
    "binding": "ASSETS"
  }
}

4. compatibility_date が古い

nodejs_compat フラグは任意の日付でも指定できますが、2024-09-23 以降で nodejs_compat_v2 が自動有効化されます。@opennextjs/cloudflare は v2 前提で書かれているため、結果的に compatibility_date: "2024-09-23" 以降が実質必須です。新規プロジェクトなら執筆時点の最新(例: 2026-04-01)に合わせておくのが安全です。

5. next/image が本番で動かない

ローカル(next dev)では動くのに、Workers にデプロイすると next/image が 404 や 500 を返す — よくある症状です。Cloudflare Workers は Vercel の Image Optimization を内蔵しないため、Cloudflare Images または外部の loader を明示的に設定する必要があります。

next.config.tsimages.loaderimages.loaderFile を設定するか、画像を <img> で直接提供する割り切りもよく使われます。小規模プロジェクトなら後者で十分です。

6. Middleware → Proxy のリネームと Node ランタイム化に追従していない

Next.js 16 で middleware.tsproxy.ts にリネームされ、Node.js runtime が既定になりました(15.x 系の middleware と Edge runtime 前提はサポートされるが非推奨)。古い記事・テンプレートをベースに組むと、ファイル名や runtime 指定でハマります。

  • Vercel の Edge Function の「1 MiB」制限を Next.js 本体の仕様と勘違いしない(これは Vercel プラットフォーム固有の値)
  • Cloudflare Workers のスクリプト上限は Free 3 MiB / Paid 10 MiB(いずれも圧縮後)
  • proxy.ts に重いライブラリ(bcrypt、全機能 jose、巨大 i18n 辞書)を抱え込ませないのは引き続き鉄則。必要なら Route Handler へ逃がす

7. 古い「TCP が張れない」認識で Postgres / Prisma を組む

Cloudflare Workers は 2023 年に cloudflare:socketsconnect() API を公開しており、生の TCP ソケットを張れます。Postgres は pg + Prisma driver adapter 経由で、Cloudflare 上から直接接続可能です。

ハマるのは、Node の net モジュールに直接依存した古いライブラリや、旧来の Prisma 既定(driver adapter 未使用)のまま移植しようとするケース。現実的な選択肢は次のとおり。

  • Cloudflare D1 (SQLite) — もっとも軽量、 Workers Paid の枠内で動く
  • Hyperdrive 経由の Postgres — 既存 Postgres を低レイテンシで繋げる公式経路
  • Neon / Supabase の HTTP driver(例: @neondatabase/serverless)— TCP を使わない serverless 向け設計で、Edge/Node どちらでも素直
  • pg + Prisma driver adapter — Postgres 直接接続、driver adapter を使う

プロジェクト初期に「どれを使うか」を決めて、ローカルと本番で同じアダプタを踏むようにするのが事故を減らすコツです。

8. 環境変数の優先順位を間違える

Next.js 自身の .env.local / .env.production と、Wrangler の vars / secrets / Workers Dashboard の Environment Variables — 3 つの系統があります。

  • ビルド時に埋め込みたい値(NEXT_PUBLIC_*): Next.js 側の .env* に置く
  • サーバー実行時に読む値 / 秘密情報: wrangler secret put で Workers Secrets に登録
  • Dashboard から編集したい値: Workers の Environment Variables(非機密用途)

同じキーを複数箇所に置くと、どれが効いているか追跡できなくなるので、運用ルールを最初に決めるのが一番コストが低いです。

9. ISR / Revalidation が Vercel と違う

Next.js の ISR は Vercel 上での動作が基準で、Cloudflare Workers では Next のキャッシュ機構と Workers のキャッシュ(Cache API / KV)の関係を自分で設計する必要があります。@opennextjs/cloudflare は incremental cache の backend を差し替えられる設計ですが、デフォルトで Vercel と同じ挙動になるわけではない点は最初から織り込んでおいてください。

10. 開発時(next dev)と本番(workerd)の挙動差で気づくのが遅れる

ローカルの next dev は Node.js で動き、本番は workerd ランタイムです。環境差に起因するバグは wrangler dev を使って早い段階で検出するのが定石です。

# @opennextjs/cloudflare の開発フロー
pnpm build           # next build
pnpm opennextjs-cloudflare build   # OpenNext が .open-next/ を生成
wrangler dev         # ← workerd ランタイムで実行 (本番と同じ挙動)
wrangler deploy      # 本番反映

CI にも wrangler dev 起動 → スモークテスト を挟むと、本番でしか出ないバグがデプロイ前に捕まります。

まとめ

Cloudflare での Next.js 運用は 2024 年後半で “正解” が Workers に寄ったのが実情です。新規プロジェクトなら @opennextjs/cloudflare + Workers 一択、既存 @cloudflare/next-on-pages + Pages 環境は急ぐ必要はないものの中長期で移行候補、という整理が 2026-04 時点の定石です。

次回は TypeScript + Zod でエッジランタイム向け型安全 API を書く予定です。

参考

記事で登場したコードをひとつの最小リポジトリとしてまとめました。ファイルツリーから切り替えて、全体の構造をそのまま確認できます。

$cat./wrangler.jsoncjsonc
{
  "$schema": "node_modules/wrangler/config-schema.json",
  "name": "nextjs-cloudflare-starter",
  "main": ".open-next/worker.js",

  // nodejs_compat を有効にするため、compatibility_date は 2024-09-23 以降が必要。
  "compatibility_date": "2026-04-01",
  "compatibility_flags": ["nodejs_compat"],

  "assets": {
    "directory": ".open-next/assets",
    "binding": "ASSETS"
  },

  "observability": {
    "enabled": true
  }

  // サーバーサイドで参照する秘密情報は wrangler secret put で。
  //   wrangler secret put DATABASE_URL
  //   wrangler secret put SOME_API_KEY
  //
  // NEXT_PUBLIC_* のビルド時埋め込み値は .env.local / .env.production に。
}
slugnextjs-cloudflare-deploy-pitfallsfiles8click a file in the tree to switch