Next.js on Cloudflare Pages から Cloudflare Workers に移行してみた

どうも白澤です。
クライアントさんの Web サイトで Next.js on Cloudflare Pages なプロジェクトがあるのですが、これを Cloudflare Workers に移行してみました。
なぜ今まで移行しなかったのか
今までの記事で何度か触れていますが、Novalumo のコーポレートサイトは Next.js on Cloudflare Pages で運用しています。個人的に Novalumo のコーポレートサイトは試験的にいろんな技術を使う場としても使っているので、過去に一度 Cloudflare Pages から Cloudflare Workers に移行しようとしたことがありました。
しかし、かなりプロジェクトとしてサイズが大きいため、Workers のサイズ制限 (最大 3MB くらい?) に引っかかってしまい、移行を断念していました(結局色々あった末に移行できたので、その話は別の記事で書きます)。
今回移行してみたプロジェクトはあまりサイズ的には大きくなかったことや、Pages でデプロイする際に必要な @cloudflare/next-on-pages
はどうやら Next.js 14 くらいしかサポートしていないようなので(ちゃんと調べてませんが結局は新しい方が良いかなと思って)移行を決意しました。
移行の手順
移行の手順は大きく以下の通りです。
- Wrangler CLI のアップデート
@opennextjs/cloudflare
のインストールwrangler.jsonc
の設定- デプロイ・動作確認
- Pages プロジェクトの削除
1. Wrangler CLI のアップデート
今回作業した時に気づいたのですが、Wrangler CLI のバージョンが 3.x を使っていました。4.x じゃなかったっけ、、、と思いながらも 4.x にアップデートしました。
bun add -d wrangler
2. @opennextjs/cloudflare
のインストール
@opennextjs/cloudflare
↗ は Cloudflare Workers 上で Next.js を動かすためのパッケージです。これをインストールすることで、Next.js のアプリケーションを Workers 上で動かすことができます。
bun add @opennextjs/cloudflare
open-next.config.ts
という設定ファイルを配置して、ドキュメント通りに設定を行います。
3. wrangler.jsonc
の設定
wrangler.toml
を採用しているプロジェクトもあるかなと思いますが、現状は JSONC で管理したい派なので wrangler.jsonc
を使っています。と、書いていて思いましたが、TOML にしても良い気がしてきた、、、
項目としては、既存の内容から
main
,assets
,services
,workers_dev
,preview_urls
,routes
の追加compatibility_date
の更新pages_build_output_dir
の削除
を行っています。
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "THE_PROJECT_NAME",
"main": ".open-next/worker.js",
"compatibility_date": "2025-xx-xx",
"compatibility_flags": ["nodejs_compat", "global_fetch_strictly_public"],
"assets": { "directory": ".open-next/assets", "binding": "ASSETS" },
"services": [
{
"binding": "WORKER_SELF_REFERENCE",
"service": "THE_PROJECT_NAME"
}
],
"workers_dev": false,
"preview_urls": true,
"routes": [
{
"pattern": "example.com",
"custom_domain": true
},
{
"pattern": "www.example.com",
"custom_domain": true
}
],
"observability": {
"enabled": true
}
}
4. デプロイ・動作確認
OpenNext では専用に 2 段階ビルドが行われます。公式ドキュメントを参考に package.json
の scripts
に以下のように追加します。
{
"scripts": {
"build": "next build", // build コマンドはそのまま
"preview": "opennextjs-cloudflare build && opennextjs-cloudflare preview",
"deploy": "opennextjs-cloudflare build && opennextjs-cloudflare deploy",
"upload": "opennextjs-cloudflare build && opennextjs-cloudflare upload"
}
}
opennextjs-cloudflare build
を実行すると next build
が先に実行され、その後に OpenNext のビルドが行われます。opennextjs-cloudflare deploy
を実行すると、wrangler
で設定した通りに Workers にデプロイされます。
基礎的なところですが、注意点としては Wrangler CLI のログインセッション的なものが切れている場合などは、デプロイ時にエラーが出るので、その際は
wrangler login
しなおしてあげると良いです。
5. Pages プロジェクトの削除
Cloudflare Workers に移行したら、Cloudflare Pages のプロジェクトを削除します。管理画面からサクッと削除しようかなーと思ったらこんなエラーが。
どうやら Pages のプロジェクトはデプロイ履歴が多い (over 100 of deployments) と削除できないようです。さてとドキュメント ↗を読みますかね。
やることは以下。
- ドキュメントに記載の zip ファイルをダウンロード
- 解凍してその中で
npm install
- 削除コマンドを実行 (要 Cloudflare API Token)
CF_API_TOKEN=<YOUR_CF_API_TOKEN> CF_ACCOUNT_ID=<ACCOUNT_ID> CF_PAGES_PROJECT_NAME=<PROJECT_NAME> npm start
実行していい感じに動くとこんな感じ:
> delete-all-deployments@1.0.0 start
> node index.js
Found live production deployment to exclude from deletion: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Listing all deployments, this may take a while...
Skipping production deployment: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Deleted deployment xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx for project THE_PROJECT_NAME
Deleted deployment xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx for project THE_PROJECT_NAME
Error: You cannot delete an aliased deployment without a `?force=true` parameter in the API request URL.
at deleteDeployment (~/repos/delete-all-deployments/index.js:54:11)
at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
at async main (~/repos/delete-all-deployments/index.js:139:9)
Deleted deployment xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx for project THE_PROJECT_NAME
Error: You cannot delete an aliased deployment without a `?force=true` parameter in the API request URL.
at deleteDeployment (~/repos/delete-all-deployments/index.js:54:11)
at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
at async main (~/repos/delete-all-deployments/index.js:139:9)
Deleted deployment xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx for project THE_PROJECT_NAME
Deleted deployment xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx for project THE_PROJECT_NAME
Deleted deployment xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx for project THE_PROJECT_NAME
Deleted deployment xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx for project THE_PROJECT_NAME
Deleted deployment xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx for project THE_PROJECT_NAME
Error: You cannot delete an aliased deployment without a `?force=true` parameter in the API request URL.
at deleteDeployment (~/repos/delete-all-deployments/index.js:54:11)
at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
at async main (~/repos/delete-all-deployments/index.js:139:9)
Deleted deployment xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx for project THE_PROJECT_NAME
Deleted deployment xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx for project THE_PROJECT_NAME
Error: You cannot delete an aliased deployment without a `?force=true` parameter in the API request URL.
at deleteDeployment (~/repos/delete-all-deployments/index.js:54:11)
at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
at async main (~/repos/delete-all-deployments/index.js:139:9)
Deleted deployment xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx for project THE_PROJECT_NAME
結構数が多いので端折りましたが、いい感じに削除されました。途中で出ているエラーの分は管理画面から見て残っているのを確認できました。これはドキュメントに記載の通り、CF_DELETE_ALIASED_DEPLOYMENTS=true
を先ほどのコマンドの環境変数に追加して再度実行すれば削除されるようです。(再実行したら消えました)
まとめ
結構簡単でしたが、ちょっとだけ初見殺し的なところがあったり、ドキュメントを読まないといけなかったりでちょっと面倒でしたね、、、
とはいえ、Cloudflare Workers の方がこれから優先されていくことになるので、移行してよかったかなと思っています。
多分次の記事では Novalumo のコーポレートサイトも Workers に移行した話を書くことになると思いますが、どちらかというと Workers 移行よりも(ネタバレになりますが)monorepo 化の方がメインになりそうです。