【設定・環境構築】OpenNext でNext.js SSGサイトをCloudflare Workersにデプロイする完全ガイド

この記事でわかること
- OpenNext を使って Next.js を Workers で動かすセットアップ一式
- generateStaticParams で SSG するときにビルドがレート制限に当たらないようにする工夫
- Workers 無料プランの CPU 10ms では動かないことと、有料プランで何が変わるか
- そして、この構成をこの後 Pages に戻した理由
Next.js(App Router)のプロジェクトと Cloudflare アカウント。Workers 有料プラン(月 5 ドル)が実質必須です。
概要: @opennextjs/cloudflareを使ってNext.jsのSSGサイトをCloudflare Workersにデプロイする方法を解説します。セットアップからSSG対応、CI/CD構築まで、本番運用に必要な設定を網羅しています。
はじめに
Cloudflare Pages で Next.js サイトを運用していましたが、microCMS から Notion API への移行に伴って Node.js ランタイムが必要になり、Edge Runtime の制約が厳しくなりました。OpenNext(@opennextjs/cloudflare)を使えば Node.js 互換で Cloudflare Workers 上で Next.js が動きます。
1. なぜOpenNextか
@cloudflare/next-on-pages の制約
@cloudflare/next-on-pagesはCloudflare Pages向けのアダプターだが、以下の制約がある:
- Edge Runtime必須: すべてのルートが
export const runtime = 'edge'を要求される - Node.js APIが使えない:
crypto,fs,path等のNode.jsモジュールが利用不可 - npm パッケージの制約: Node.js APIに依存するパッケージ(@notionhq/client, cheerio等)が動かない
OpenNextのアプローチ
@opennextjs/cloudflareはCloudflare WorkersのNode.js互換モードを活用し、Next.jsをほぼそのまま動かす。
- Node.js APIが使える(crypto, Buffer等)
- npm パッケージの互換性が高い
- ISR / SSG / SSR すべてサポート
2. セットアップ
インストール
npm install @opennextjs/cloudflare
npm install -D wrangler
# esbuildの明示的インストールが必要
npm install -D esbuildopen-next.config.ts
import { defineCloudflareConfig } from '@opennextjs/cloudflare';
export default defineCloudflareConfig({});wrangler.toml
#:schema node_modules/wrangler/config-schema.json
name = "kt-tech-blog"
main = ".open-next/worker.js"
compatibility_date = "2025-03-14"
compatibility_flags = ["nodejs_compat"]
[assets]
directory = ".open-next/assets"
binding = "ASSETS"
# KVはISRキャッシュに使用
[[kv_namespaces]]
binding = "NEXT_CACHE_WORKERS_KV"
id = "your-kv-namespace-id"package.json のスクリプト更新
{
"scripts": {
"build": "opennextjs-cloudflare",
"dev": "next dev",
"deploy": "opennextjs-cloudflare && wrangler deploy",
"preview": "opennextjs-cloudflare && wrangler dev"
}
}3. SSG対応
generateStaticParamsで全ページパスを生成
SSGでは、ビルド時に全ページのパスを静的に生成する必要がある。
// src/app/blogs/[blogId]/page.tsx
export async function generateStaticParams() {
const allBlogs = await getAllBlogs(); // Notion APIから全記事取得
return allBlogs.map((blog) => ({
blogId: blog.id,
}));
}ビルドワーカー数を1に制限
Notion APIにはレート制限(3リクエスト/秒)があるため、ビルド時の並列度を制限する。
// next.config.js
module.exports = {
experimental: {
workerThreads: false,
cpus: 1, // ビルドワーカー数を1に制限
},
};API呼び出し間隔の制御
// libs/notion.ts
const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
export async function getAllBlogs(): Promise<Blog[]> {
const pages = [];
let cursor: string | undefined;
do {
const response = await notion.dataSources.query({
data_source_id: DATABASE_ID,
start_cursor: cursor,
});
pages.push(...response.results);
cursor = response.next_cursor ?? undefined;
await delay(350); // 350ms間隔でAPI呼び出し
} while (cursor);
return pages.map(pageToBlog);
}4. CI/CD — GitHub Actions
ワークフロー定義
# .github/workflows/deploy.yml
name: Deploy to Cloudflare Workers
on:
push:
branches: [main]
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- name: Build with OpenNext
run: npx opennextjs-cloudflare
env:
NOTION_TOKEN: ${{ secrets.NOTION_TOKEN }}
NOTION_DATABASE_ID: ${{ secrets.NOTION_DATABASE_ID }}
- name: Deploy to Cloudflare Workers
run: npx wrangler deploy
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}Worker Secretsの同期
ランタイムで使用する環境変数はWorker Secretsに設定する必要がある。
# Worker Secrets に環境変数を設定
# 引数なしで実行し、プロンプトに値を貼る(履歴に残さない)
npx wrangler secret put NOTION_TOKEN
npx wrangler secret put NOTION_DATABASE_ID5. Workers有料プランが必要
無料プランの制約
Cloudflare Workers無料プランにはCPU時間10msの制限がある。Next.jsのSSRレンダリングはこの制限を大幅に超えるため、無料プランでは動作しない。
エラー例
Error 1102: Worker exceeded CPU time limit有料プラン($5/月)
Workers Paid プラン($5/月)にアップグレードすると:
- CPU時間: 10ms → 30秒
- リクエスト数: 10万/日 → 1000万/月
- Workers KV: 読み取り10万/日 → 1000万/月
個人ブログの規模であれば$5/月で十分運用可能。
Tips
esbuild の明示的インストールが必要。OpenNext のビルドプロセスで使用されるが、peer dependency として自動インストールされないことがあるwrangler dev でローカルプレビューする際は .dev.vars ファイルに環境変数を設定する(.gitignore への追加を忘れずに)wrangler.toml に書いてよいが、API トークン等の secret は絶対に書かない(リポジトリに入る)参考リンク
- OpenNext Cloudflare
- Cloudflare Workers: 制限
- Cloudflare Workers→Pages出戻り記(別記事)
- GitHub Actions で Cloudflare Workers への CI/CD パイプラインを構築する(別記事)
まとめ
- OpenNextを使えばCloudflare Workers上でNext.jsがNode.js互換で動作する
- SSG対応はgenerateStaticParamsで全パスを生成し、ビルドワーカー数を制限する
- CI/CDはGitHub Actions + wrangler deployで簡単に構築可能
- Workers有料プラン($5/月) が必須。無料プランのCPU 10ms制限では動かない
- Worker Secretsの設定を忘れると503エラーが大量発生するので注意
更新履歴
- この後 Pages に戻したことを冒頭に明記し、判断の根拠記事へリンク。delay が必要なのはビルド時だけで、ランタイムに入れると TTFB に乗ることを補足。echo "トークン" | wrangler secret put を引数なし実行に修正(シェル履歴対策)。壊れていた目次マーカーを自動目次に差し替え。エラーのコードブロックの言語指定を text に修正。引用形式の Tips を callout に統一。参考リンクの節を新設。箸条書きだった「はじめに」を文章に整理。


