[Cloudflare] Cloudflare PagesからWorkersへNext.jsプロジェクトを移行した時の手順メモ

なぜPagesからWorkersに移行するのか

Cloudflare PagesでNext.jsを動かすには@cloudflare/next-on-pagesを使う必要があるが、制約が多い。

  • すべての非静的ルートにexport const runtime = 'edge'の指定が必須
  • fspathなどのNode.js APIが使えない
  • Edge Runtime前提のため、使えないライブラリがある

Cloudflareは公式にNext.jsプロジェクトにはWorkersを推奨しており、Workers向けアダプター@opennextjs/cloudflareを提供している。Workersではnodejs_compatフラグによりNode.js APIが利用可能になり、Pagesよりも柔軟にNext.jsを動かせる。

移行手順

1. パッケージの入れ替え

@cloudflare/next-on-pagesを削除し、@opennextjs/cloudflarewranglerをインストールする。

yarn remove @cloudflare/next-on-pages
yarn add -D @opennextjs/cloudflare wrangler

2. wrangler.jsoncの作成

プロジェクトルートにwrangler.jsoncを作成する。

{
  "$schema": "node_modules/wrangler/config-schema.json",
  "main": ".open-next/worker.js",
  "name": "my-project",
  "compatibility_date": "2026-02-13",
  "compatibility_flags": ["nodejs_compat"],
  "assets": {
    "directory": ".open-next/assets",
    "binding": "ASSETS"
  }
}
  • nameはCloudflare上のプロジェクト名と一致させる
  • compatibility_flagsnodejs_compatを指定することでNode.js APIが利用可能になる
  • assetsは静的ファイルの配信設定

3. open-next.config.tsの作成

プロジェクトルートにopen-next.config.tsを作成する。

import { defineCloudflareConfig } from "@opennextjs/cloudflare";
import staticAssetsIncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/static-assets-incremental-cache";
 
export default defineCloudflareConfig({
  incrementalCache: staticAssetsIncrementalCache,
  enableCacheInterception: true,
});

staticAssetsIncrementalCacheはSSGで生成されたページをキャッシュするための設定である。

4. ビルド・デプロイコマンドの変更

package.jsonのスクリプトを更新する。

{
  "scripts": {
    "build": "next build",
    "preview": "opennextjs-cloudflare build && opennextjs-cloudflare dev",
    "deploy": "opennextjs-cloudflare build && opennextjs-cloudflare deploy"
  }
}

5. .gitignoreに追加

ビルド成果物のディレクトリを除外する。

.open-next/

すでに追跡済みの場合は、インデックスから削除する。

git rm --cached -r .open-next

6. next.config.mjsの調整

Pages向けの設定を削除し、Workers向けに調整する。

Pages向けの設定(setupDevPlatformexperimental.pprなど)を削除し、以下のようにWorkersで必要な設定を追加する。

// Before(Pages向け)
const nextConfig = {
  experimental: {
    ppr: true,
  },
};
 
// After(Workers向け)
const nextConfig = {
  bundlePagesRouterDependencies: true,
  serverExternalPackages: [],
};

Cloudflareダッシュボードでの設定

Workersプロジェクトの作成

  1. CloudflareダッシュボードでWorkers & Pagesを開く
  2. Create > Workersを選択
  3. 「Import a repository」 からGitリポジトリを接続する(GitHubまたはGitLabとの連携が必要)
  4. ビルドコマンド: yarn prebuild && npx opennextjs-cloudflare build
  5. デプロイコマンド: npx opennextjs-cloudflare deploy

プロジェクト名の注意点

既存のPagesプロジェクトと同じ名前は使えない。

  • 一時的に別名(例: my-project-web)で作成し、Pages削除後にリネームする
  • または先にPagesプロジェクトを削除してから同じ名前でWorkersを作成する

環境変数の移行

Pagesで設定していた環境変数はWorkers側にも再設定が必要。ダッシュボードのSettings > Variables and Secretsから追加する。APIキーなどのシークレットは「Encrypt」オプションで設定する。

カスタムドメインの付け替え

  1. Pages側でカスタムドメインを解除
  2. Workers側で同じカスタムドメインを設定
  3. DNSの反映は数分〜数十分程度で完了する

ハマりどころ:next-mdx-remoteはWorkersで動かない

next-mdx-remoteは内部でeval()を使用している。eval()文字列として渡したJavaScriptコードをその場で実行する関数で、Cloudflare Workersのランタイム(workerd)はセキュリティ上の理由からこれを許可していないため、以下のエラーが発生する。

Failed to load external module next-mdx-remote

対策

  • ビルド時にMDXをコンパイルする: unified / remark / rehypeを使ってビルドスクリプトでMDXをHTMLに変換し、JSONとして出力する
  • MDXを使わない構成にする: マークダウンパーサーを直接利用する

next-mdx-remote-clientも内部でeval()を使っているため、同様に動作しない点に注意。

ハマりどころ:Resendのメール送信で403エラー

Workersへ移行後、コンタクトフォームからのメール送信が500エラーで失敗した。

エラーログの確認

ターミナルで以下のコマンドを実行し、リアルタイムログを確認する。

npx wrangler tail <プロジェクト>

ログに以下のエラーが記録されていた。

Resend error response: 403
{"statusCode":403,"message":"Not authorized to send emails from gmail.com"}

原因

Resendは送信元(from)にフリーメールのドメインを許可していないgmail.comyahoo.co.jpなどのアドレスをfromに指定すると403エラーになる。

これはWorkers移行とは直接関係なく、Resendの仕様による制約。Pages時代に別のWorkers(ofurousagi-contact-api)で動かしていた場合も同様のエラーが発生し得る。

解決方法

  1. Resendダッシュボードで自分のドメインを登録する
  2. Cloudflare DNSにResendが指定するDNSレコード(TXT、CNAME、MX)を追加する
  3. ドメイン認証が完了したら、環境変数RESEND_FROMを変更する
# 変更前(403エラー)
RESEND_FROM="Contact <myname@gmail.com>"

# 変更後(認証済みドメインを使用)
RESEND_FROM="Contact <noreply@mydomain.com>"

まとめ

  • CloudflareはNext.jsに対してPagesではなくWorkersを推奨している(PagesはEdge Runtime前提で制約が多く、Workersはnodejs_compatによりNode.js API互換を広げられるため)
  • 移行は@opennextjs/cloudflare + wranglerのインストールと設定ファイルの追加で完了する
  • next-mdx-remoteのようなeval()を使うライブラリはWorkersでは動作しない
  • Resendでメール送信する場合、送信元に独自ドメインの認証が必須(Gmail不可)
  • npx wrangler tailでリアルタイムログを確認できるため、デバッグに活用する

補足: wrangler tailでログを流していると、GET /.envGET /.git/configなど外部ボットによる脆弱性スキャンのアクセスが大量に記録される。サイトの動作には影響しない。Cloudflare Workersでは静的ファイルとして配置していないパスはNext.jsのルーティングで処理されるため、実ファイルが漏れる心配は基本的にない。