CloudflareにNext.jsをデプロイする(前編)〜環境構築から初回デプロイまで
Next.jsをデプロイするとき、まず候補に上がるのがVercelですが、
今回はあえてCloudflareにデプロイしてみました。
やってみた結果、思ったよりスムーズにできたので、手順をまとめておきます。
前編では環境構築から初回デプロイ、GitHub連携まで。後編では環境変数やカスタムドメイン、ISR/SSRまわりの実践設定を扱います。
目次
なぜCloudflareなのか
VercelはNext.jsの開発元なので、当然いちばん相性がいいです。
ただ、気になるのがコスト面でした。
- Vercel:帯域100GBまで無料、超えると従量課金(Proプランは月$20〜)
- Cloudflare Workers:帯域無制限・無料。リクエスト数ベースの課金(無料枠10万リクエスト/日)
個人ブログや小規模サービスならVercelの無料枠で十分ですが、
トラフィックが読めないサービスだと、Cloudflareの「帯域無制限」はかなり安心感があります。
あとCloudflareは、CDNが世界330箇所以上にあるので、グローバルなレスポンスも速いです。
「Vercelじゃないとダメ」な理由がなければ、選択肢としてアリだなと思いました。
前提:今はOpenNextが公式推奨
以前はCloudflareにNext.jsをデプロイするには @cloudflare/next-on-pages を使っていましたが、
これは現在非推奨(deprecated)になっています。
2025年以降の公式推奨は @opennextjs/cloudflare です。
大きな違いはこのあたりです。
next-on-pages:Edge Runtimeのみ対応 → 制約が多い@opennextjs/cloudflare:Node.jsランタイム対応 → Next.jsの機能をほぼフルに使える
ISR、SSR、App Routerなど、Next.jsの主要機能がちゃんと動くようになったのが大きいです。
この記事ではOpenNextを使って進めます。
Cloudflareアカウントの準備
まだアカウントがない場合は、Cloudflare公式サイトからサインアップします。
無料プランで十分です。
サインアップ後、ダッシュボードにログインできればOKです。
あとで使うので、Account IDをメモしておくと便利です(ダッシュボードの右サイドバーに表示されています)。
Next.jsプロジェクトを作成する
Cloudflare公式のスキャフォールドを使うと、最初からOpenNextの設定が入った状態で始められます。
npm create cloudflare@latest -- my-next-app --framework=next --platform=workers
これで、Next.js(App Router)+ OpenNext + wrangler設定ファイルが一式生成されます。
もし既存のNext.jsプロジェクトに導入する場合は、手動でセットアップします。
既存プロジェクトへの導入
まず、パッケージをインストールします。
npm install --save-dev @opennextjs/cloudflare wrangler
open-next.config.ts を作成
プロジェクトルートに open-next.config.ts を作ります。
import { defineCloudflareConfig } from "@opennextjs/cloudflare";
export default defineCloudflareConfig();
これが最小構成です。ISRのキャッシュ設定などは後編で詳しく触れます。
wrangler.jsonc を作成
プロジェクトルートに wrangler.jsonc を作ります。
(wrangler.toml でも動きますが、Cloudflareは現在JSONCを推奨しています)
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "my-next-app",
"main": ".open-next/worker.js",
"compatibility_date": "2025-04-01",
"compatibility_flags": ["nodejs_compat"],
"assets": {
"directory": ".open-next/assets",
"binding": "ASSETS"
}
}
ポイントは2つです。
compatibility_flagsに"nodejs_compat"を入れること(必須)compatibility_dateを"2025-04-01"以降にすること(これより前だとprocess.envが空になります)
package.json にスクリプトを追加
{
"scripts": {
"dev": "next dev",
"build": "next build",
"preview": "opennextjs-cloudflare build && opennextjs-cloudflare preview",
"deploy": "opennextjs-cloudflare build && opennextjs-cloudflare deploy"
}
}
preview はローカルでCloudflare環境を再現して動作確認できるコマンドです。
デプロイ前に npm run preview で確認しておくと安心です。
ローカルでプレビューしてみる
まずはローカルで動くか確認します。
npm run preview
これを実行すると、内部的に以下が走ります。
next buildでNext.jsのビルド- OpenNextがビルド出力をCloudflare Workers形式に変換
- Wranglerがローカルで起動(デフォルトは
http://localhost:8787)
ブラウザで開いて、ちゃんと表示されればOKです。
手動デプロイ
ローカルで確認できたら、いよいよCloudflareにデプロイします。
npm run deploy
初回はブラウザが開いてCloudflareへのログイン認証が求められます。
認証が通ると、自動でデプロイが始まります。
デプロイが成功すると、こんな感じのURLが発行されます。
https://my-next-app.YOUR_SUBDOMAIN.workers.dev
このURLにアクセスして、表示されていれば成功です。
GitHub連携での自動デプロイ
手動デプロイでも十分ですが、pushしたら自動デプロイされるようにしておくと楽です。
方法は2つあります。
方法1:Cloudflareダッシュボードからの連携
Cloudflareダッシュボードの「Workers & Pages」から、GitHubリポジトリを直接連携できます。
- Cloudflareダッシュボード →「Workers & Pages」→「Create」
- 「Import a Repository」でGitHubと連携
- リポジトリを選択
- ビルドコマンドに
npx opennextjs-cloudflare buildを設定 - デプロイ
これでmainブランチにpushするたびに自動デプロイされます。
いちばん手軽な方法です。
方法2:GitHub Actionsを使う
テストを挟んだり、デプロイ条件を細かく制御したい場合は、GitHub Actionsで自分でワークフローを書くこともできます。
name: Deploy to Cloudflare Workers
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
- run: npm ci
- run: npx opennextjs-cloudflare build
- run: npx wrangler deploy
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
GitHubリポジトリの Settings → Secrets and variables → Actions から、CLOUDFLARE_API_TOKEN と CLOUDFLARE_ACCOUNT_ID を登録しておきます。
APIトークンは、Cloudflareダッシュボードの「My Profile」→「API Tokens」から
「Edit Cloudflare Workers」テンプレートで作成できます。
ハマりポイント(前編)
ここからは自分が実際にハマった(orハマりそうになった)ポイントです。
compatibility_date が古いと process.env が空になる
compatibility_date が "2025-04-01" より前だと、process.env に環境変数が入りません。
ネットの古い記事を参考にすると古い日付が書かれていることがあるので、なるべく最新の日付にしておくのが安心です。
Edge Runtimeは使わない
OpenNextを使う場合、export const runtime = "edge" は書かないようにします。
Node.jsランタイムを使う前提なので、Edge指定があるとエラーになります。
もし既存プロジェクトに runtime = "edge" が残っていたら、全部削除する必要があります。
Workerのサイズ制限に注意
Cloudflare Workersにはサイズ制限があります。
- 無料プラン:3 MiB
- 有料プラン($5/月〜):10 MiB
大きなライブラリを含むプロジェクトだと、無料プランでは収まらないことがあります。
そのときは有料プランを検討するか、依存を減らす工夫が必要です。
グローバルなDBクライアントは使えない
Cloudflare Workersでは、リクエストをまたいでI/Oオブジェクトを共有できません。
たとえば、グローバルスコープでDBクライアントを初期化してリクエスト間で使い回す…というパターンはエラーになります。
// NG: グローバルで初期化して使い回す
const db = new Database();
export async function GET() {
const data = await db.query("SELECT * FROM users");
return Response.json(data);
}
// OK: リクエストごとに作る
export async function GET() {
const db = new Database();
const data = await db.query("SELECT * FROM users");
return Response.json(data);
}
「Cannot perform I/O on behalf of a different request」というエラーが出たら、これが原因です。
まとめ
前編では、OpenNextを使ってNext.jsをCloudflare Workersにデプロイする基本的な流れを紹介しました。
- 今は
@opennextjs/cloudflareが公式推奨(next-on-pagesは非推奨) open-next.config.tsとwrangler.jsoncを用意すればOKnpm run deployで手動デプロイ、GitHub連携で自動デプロイも簡単- Edge Runtimeは使わない、compatibility_dateは新しめに設定する
後編では、環境変数の設定、カスタムドメインの接続、ISR/SSR/Staticの使い分け、
キャッシュ戦略(R2を使ったISR)など、実践的な設定を紹介します。
今回は以上です!