経緯
ある日、自分で使っているwebtoolsというツールを寄せ集めたシンプルなnext.jsプロジェクトにアクセスすると、ルートページ以外が404になっていました。
きっとCloudflare側の問題なのでしょうし、デプロイもその他のアップロードもログを見る限りは確実になされていたのですが、これが使えないのは困ったと思ったので、Cloudflare Workersに移行しました。
移行方法
OpenNext
以前、Pagesのデプロイにあhnext-on-pagesを使っていましたが、対応しているパッケージのバージョンが古く、OpenNextへの移行が必要でした。
しかし、手動の設定が面倒だったので(他にもnext-on-pagesで動いているものがあった)、ドキュメントの内容をそのままスクリプトにして実行しました。
https://developers.cloudflare.com/workers/framework-guides/web-apps/nextjs/
github連携がとても好きで、どうにも、ローカルのwranglerでdeployコマンドを打ってデプロイするのがあまり好きになれなくて、ずっとパネルをイジイジしています。
どういうのが良いんでしょうかね。
そもそもwranglerにOpenNextが必須なのかすら知らないです……(無知)
wrangler
OpenNextを書く時にドキュメントにwranglerの設定ファイルであるwrangler.jsoncも導入しました。が、pagesとworkersのwrangler.jsoncは違うので、書き直しました。
https://developers.cloudflare.com/workers/static-assets/migration-guides/migrate-from-pages/
ですが、此処でもまた、難しい問題が。
Workers デプロイ設定
package.jsonのスクリプト設定は次のようになっています。
"scripts": {
"dev": "next dev --turbopack",
"build": "next build --turbopack",
"testbuild": "cd ./wasm-webtools && wasm-pack build --release --target web && cd .. && next build --turbopack",
"start": "next start",
"lint": "biome check",
"format": "biome format --write",
"deploy": "opennextjs-cloudflare build && opennextjs-cloudflare deploy",
"upload": "opennextjs-cloudflare build && opennextjs-cloudflare upload",
"preview": "opennextjs-cloudflare build && opennextjs-cloudflare preview",
"cf-typegen": "wrangler types --env-interface CloudflareEnv ./cloudflare-env.d.ts"
},
cf-typegenコマンドなどのdeployコマンド以下のものは、npm create cloudflare@latest -- my-next-app --framework=nextで生成したダミープロジェクトから引っ張ってきたものです。
ここで問題なのは、buildコマンドはnext.jsのビルドコマンドですが、opennextjs-cloudflare buildコマンドはOpenNextのビルドコマンドです。
OpenNextのビルドコマンドを実行すると、.opennextディレクトリが生成され、nextのビルド結果とは違います。
Cloudflare WorkersのNext.js向けのテンプレート設定を適応すると、
build: npm run build
deploy: wrangler deploy
となっていて、なんと、nextのビルド結果がopennextのビルド結果としてwranglerに渡されてしまいます。
nextのビルド結果は.opennextディレクトリに出力されているので、そのさきのworkers.jsが存在しないというところでエラーが起きます。
なので、私はCloudflare WorkersのNext.js向けのテンプレート設定を適応するのをやめて以下のように変更しました。
build:
deploy: bunx run deploy
という方式にしました。
力技だし、他に良い方法が在るような気もします。
下手にOpenNextを導入してしまったため、上記ページ
https://developers.cloudflare.com/workers/static-assets/migration-guides/migrate-from-pages/
にかかれているwrangler.jsoncが適応できませんでした。
このため、これもダミー生成したプロジェクトからwrangler.jsoncをコピーして追加することで解決させました。
/**
* For more details on how to configure Wrangler, refer to:
* https://developers.cloudflare.com/workers/wrangler/configuration/
*/
/**
* For more details on how to configure Wrangler, refer to:
* https://developers.cloudflare.com/workers/wrangler/configuration/
*/
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "my-next-app",
"main": ".open-next/worker.js",
"compatibility_date": "2026-07-30",
"compatibility_flags": [
"nodejs_compat",
"global_fetch_strictly_public"
],
"assets": {
"binding": "ASSETS",
"directory": ".open-next/assets"
},
"images": {
// Enable image optimization
// see https://opennext.js.org/cloudflare/howtos/image
"binding": "IMAGES"
},
"services": [
{
// Self-reference service binding, the service name must match the worker name
// see https://opennext.js.org/cloudflare/caching
"binding": "WORKER_SELF_REFERENCE",
"service": "my-next-app"
}
],
"observability": {
"enabled": true
},
"upload_source_maps": true
/**
* Smart Placement
* https://developers.cloudflare.com/workers/configuration/smart-placement/#smart-placement
*/
// "placement": { "mode": "smart" }
/**
* Bindings
* Bindings allow your Worker to interact with resources on the Cloudflare Developer Platform, including
* databases, object storage, AI inference, real-time communication and more.
* https://developers.cloudflare.com/workers/runtime-apis/bindings/
*/
/**
* Environment Variables
* https://developers.cloudflare.com/workers/wrangler/configuration/#environment-variables
* Note: Use secrets to store sensitive data.
* https://developers.cloudflare.com/workers/configuration/secrets/
*/
// "vars": { "MY_VARIABLE": "production_value" }
}
ちなみに、これの生成日は2026-07-30でしたが、bunx wrangler previewを実行した時に2026-07-29にせよというエラーが出ました。
実行したのは日本時間で13時過ぎだったので、UTCでも日付を超えているはずなんですけどね。
Pages削除
Cloudflare Pagesのプロジェクトを削除しようとしたら、
Your project has too many deployments to be deleted, follow this guide to delete them: https://cfl.re/3CXesln
とでました。
ページのハイライト位置まで出してくれてたらいいのに。
https://developers.cloudflare.com/pages/platform/known-issues/#delete-a-project-with-a-high-number-of-deployments
なんでもデプロイメントが多いと削除できない問題があるらしいです。
ここに載っているスクリプトを実行しました。
shって書いてあるのに、shだと動かなくてbash仕様のスクリプトなんですよね。
動かなかったです。
bashが入っているのって私の手元だと開発用VMだけだったのでそこに行って実行したら、wranglerにログインしてなかったんです。
ssh接続なので、うまくログインできず、手元のwindowsで実行するためにシェルスクリプトを書き直しました。
def delete-pages-deployments [project_name: string] {
mut prod_id = ""
loop {
print "Fetching deployment list..."
# 外部コマンドの出力をそのままテーブルへ変換
let deployments = (
with-env { CI: "true" } {
bunx wrangler pages deployment list --project-name $project_name --json
} | from json
)
if ($deployments | is-empty) {
print "No deployments found."
break
}
let ids = ($deployments | get Id)
let to_delete = ($ids | where $it != $prod_id)
if ($to_delete | is-empty) {
print $"Done. Production: ($prod_id)"
break
}
print $"Deleting ($to_delete | length) deployments..."
for id in $to_delete {
let del_res = (
with-env { CI: "true" } {
bunx wrangler pages deployment delete $id --project-name $project_name --force
} | complete
)
let output = $"($del_res.stdout)\n($del_res.stderr)"
if not ($output | str contains "Successfully deleted") {
if ($output | str contains "active production deployment") {
$prod_id = $id
}
}
}
}
}
delete-pages-deployments "webtools"
私はnushellを使っているので、jsonの扱いが標準でできて非常に便利でした。冗長なこと以外は。
まとめ
推奨をコロコロ変えるのはよしてほしい。
最新の技術を導入するのは良いことなのですが、next-on-pagesがpagesのNext.js向けテンプレートの中に残っていたりと、古いところの対応がお粗末なのかなと思います。
あと、webtoolsなんてstatic HTMLでも良いものにNext.jsとWASMを導入したりしているので、昔の私のwebtoolsに対しての技術選定ミスも重大な痛手だと思いました。