mcpField
C
cloudflare-opennext

cloudflare-opennext

github.com/null-shotクラウド・DevOps0464 回インストール41 週間前に更新
リポジトリ

cloudflare-opennext について

Cloudflare OpenNext は、Next.js アプリを Cloudflare Workers にデプロイするためのアダプター兼スキルです。新規デプロイや移行を行う開発者向けで、App Router、Pages Router、ISR、SSG、Cloudflare バインディングに対応し、ビルドとプレビューのコマンドを備えています。

主な機能

  1. 01Next.js のビルド出力を Workers 向けに変換
  2. 02App Router と Pages Router に対応
  3. 03SSG・SSR・ISR に対応
  4. 04Cloudflare バインディングへのアクセス
  5. 05ビルド・プレビュー・デプロイ用コマンド

活用シーン

  1. 01新しい Next.js アプリの Workers へのデプロイ
  2. 02既存 Next.js アプリの Cloudflare への移行
  3. 03ISR または SSG のキャッシュ設定
  4. 04ルートからの Cloudflare バインディング利用

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/null-shot/cloudflare-skills --skill cloudflare-opennext

インストール後、Claude Code で/cloudflare-opennextを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
caching.md
configuration.md
database-orm.md
troubleshooting.md

詳細

Cloudflare OpenNext

@opennextjs/cloudflare アダプターを使用して、App Router、Pages Router、ISR、SSG、Cloudflare バインディングを完全にサポートする Next.js アプリケーションを Cloudflare Workers にデプロイします。

使用する場面

  • Cloudflare Workers 向けに新しい Next.js アプリを作成する場合
  • 既存の Next.js アプリを Cloudflare に移行する場合
  • R2、KV、D1 を使用した ISR/SSG キャッシュを設定する場合
  • Cloudflare バインディング(KV、R2、D1、Durable Objects、AI)にアクセスする場合
  • Next.js でデータベースや ORM(Drizzle、Prisma)を使用する場合
  • デプロイの問題やバンドルサイズの問題を解決する場合

はじめに

新しいアプリ
npm create cloudflare@latest -- my-next-app --framework=next --platform=workers
cd my-next-app
npm run dev      # Local development with Next.js
npm run preview  # Preview in Workers runtime
npm run deploy   # Deploy to Cloudflare
既存アプリの移行
# 1. Install dependencies
npm install @opennextjs/cloudflare@latest
npm install --save-dev wrangler@latest

# 2. Create wrangler.jsonc (see Configuration section)
# 3. Create open-next.config.ts
# 4. Update next.config.ts
# 5. Add scripts to package.json
# 6. Deploy
npm run deploy

コアコンセプト

OpenNext の仕組み

@opennextjs/cloudflare アダプターは次の処理を行います。

  1. next build を実行して Next.js のビルド出力を生成します
  2. ビルド出力を Cloudflare Workers ランタイムで動作するように変換します
  3. worker.js エントリーポイントを含む .open-next/ ディレクトリに出力します
  4. 静的ファイル(_next/static、public)には Workers Static Assets を使用します
Node.js ランタイム(Edge ではありません)

重要:OpenNext は Next.js の Node.js ランタイムを使用し、Edge ランタイムは使用しません。

// ❌ Remove this - Edge runtime not supported
export const runtime = "edge";

// ✅ Default Node.js runtime - fully supported
// No export needed, this is the default

Node.js ランタイムでは、次のことが可能です。

  • nodejs_compat フラグによる Node.js API との完全な互換性
  • Edge ランタイムより多くの Next.js 機能の利用
  • すべての Cloudflare バインディングへのアクセス

設定ファイル

wrangler.jsonc

OpenNext の最小構成:

{
  "$schema": "node_modules/wrangler/config-schema.json",
  "name": "my-nextjs-app",
  "main": ".open-next/worker.js",
  "compatibility_date": "2024-12-30",
  "compatibility_flags": [
    "nodejs_compat",                    // Required for Node.js APIs
    "global_fetch_strictly_public"      // Security: prevent local IP fetches
  ],
  "assets": {
    "directory": ".open-next/assets",   // Static files
    "binding": "ASSETS"
  },
  "services": [
    {
      "binding": "WORKER_SELF_REFERENCE",
      "service": "my-nextjs-app"        // Must match "name" above
    }
  ],
  "images": {
    "binding": "IMAGES"                 // Optional: Enable image optimization
  }
}

必須の設定:

  • nodejs_compat 互換性フラグ
  • compatibility_date >= 2024-09-23
  • WORKER_SELF_REFERENCE サービスバインディング(ワーカー名と一致させる必要があります)
  • main と assets のパスは変更しないでください

R2、KV、D1 バインディングを含む完全な設定については、references/configuration.md を参照してください。

open-next.config.ts

キャッシュと OpenNext の動作を設定します。

import { defineCloudflareConfig } from "@opennextjs/cloudflare";
import r2IncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache";

export default defineCloudflareConfig({
  incrementalCache: r2IncrementalCache,
});

このファイルが存在しない場合は、自動生成されます。キャッシュオプションについては、references/caching.md を参照してください。

next.config.ts

ローカル開発用に OpenNext を初期化します。

import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  // Your Next.js configuration
};

export default nextConfig;

// Enable bindings access during `next dev`
import { initOpenNextCloudflareForDev } from "@opennextjs/cloudflare";
initOpenNextCloudflareForDev();
.dev.vars

ローカル開発用の環境変数:

# .dev.vars
NEXTJS_ENV=development

NEXTJS_ENV 変数は、読み込む Next.js の .env ファイルを選択します。

  • development → .env.development
  • production → .env.production(デフォルト)

Cloudflare バインディングへのアクセス

getCloudflareContext() を使用すると、任意のルートでバインディングにアクセスできます。

import { getCloudflareContext } from "@opennextjs/cloudflare";

// Route Handler (App Router)
export async function GET(request: Request) {
  const { env, cf, ctx } = getCloudflareContext();
  
  // Access KV
  const value = await env.MY_KV.get("key");
  
  // Access R2
  const object = await env.MY_BUCKET.get("file.txt");
  
  // Access D1
  const result = await env.DB.prepare("SELECT * FROM users").all();
  
  // Access Durable Objects
  const stub = env.MY_DO.idFromName("instance-1");
  const doResponse = await stub.fetch(request);
  
  // Access request info
  const country = cf?.country;
  
  // Background tasks
  ctx.waitUntil(logAnalytics());
  
  return Response.json({ value });
}

// API Route (Pages Router)
export default async function handler(req, res) {
  const { env } = getCloudflareContext();
  const data = await env.MY_KV.get("key");
  res.json({ data });
}

// Server Component
export default async function Page() {
  const { env } = getCloudflareContext();
  const data = await env.MY_KV.get("key");
  return <div>{data}</div>;
}
非同期コンテキストを使用する SSG ルート

静的サイト生成ルートでは、非同期モードを使用します。

// In SSG route (generateStaticParams, etc.)
const { env } = await getCloudflareContext({ async: true });
const products = await env.DB.prepare("SELECT * FROM products").all();

警告:SSG の実行中は、.dev.vars のシークレットとローカルバインディングの値が静的ビルドに含まれます。機密データの取り扱いには注意してください。

TypeScript 型

バインディングの型を生成します。

npx wrangler types --env-interface CloudflareEnv cloudflare-env.d.ts

package.json に追加します。

{
  "scripts": {
    "cf-typegen": "wrangler types --env-interface CloudflareEnv cloudflare-env.d.ts"
  }
}

wrangler.jsonc のバインディングを変更した後は、毎回実行してください。

CLI コマンド

opennextjs-cloudflare CLI は、OpenNext 固有の動作を追加した Wrangler のラッパーです。

# Build the Next.js app and transform for Workers
npx opennextjs-cloudflare build

# Build and preview locally with Wrangler
npm run preview
# or
npx opennextjs-cloudflare preview

# Build and deploy to Cloudflare
npm run deploy
# or
npx opennextjs-cloudflare deploy

# Build and upload as a version (doesn't deploy)
npm run upload
# or
npx opennextjs-cloudflare upload

# Populate cache (called automatically by preview/deploy/upload)
npx opennextjs-cloudflare populateCache local   # Local bindings
npx opennextjs-cloudflare populateCache remote  # Remote bindings

推奨する package.json スクリプト:

{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "preview": "opennextjs-cloudflare build && opennextjs-cloudflare preview",
    "deploy": "opennextjs-cloudflare build && opennextjs-cloudflare deploy",
    "upload": "opennextjs-cloudflare build && opennextjs-cloudflare upload",
    "cf-typegen": "wrangler types --env-interface CloudflareEnv cloudflare-env.d.ts"
  }
}

キャッシュ戦略

OpenNext は、Cloudflare ストレージを使用した Next.js のキャッシュに対応しています。

キャッシュの種類用途ストレージの選択肢
インクリメンタルキャッシュISR/SSG のページデータR2、KV、Static Assets
キュー時間ベースの再検証Durable Objects、Memory
タグキャッシュオンデマンドの再検証D1、Durable Objects

簡単な設定例:

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

// Small Site with ISR
import r2IncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache";
export default defineCloudflareConfig({
  incrementalCache: r2IncrementalCache,
  queue: doQueue,
  tagCache: d1NextTagCache,
});

リージョナルキャッシュやシャーディングされたタグキャッシュを含む完全なキャッシュパターンについては、references/caching.md を参照してください。

画像の最適化

Cloudflare Images を有効にすると、画像を自動で最適化できます。

// wrangler.jsonc
{
  "images": {
    "binding": "IMAGES"
  }
}

Next.js の <Image> コンポーネントは、自動的に Cloudflare Images を使用します。追加料金が発生します。

互換性に関する注意事項:

  • 対応形式:PNG、JPEG、WEBP、AVIF、GIF、SVG
  • minimumCacheTTL はサポートされていません
  • dangerouslyAllowLocalIP はサポートされていません

データベースと ORM のパターン

重要なルール:Workers でグローバルなデータベースクライアントを作成しないでください。リクエストごとに作成します。

// ❌ WRONG - Global client causes I/O errors
import { Pool } from "pg";
const pool = new Pool({ connectionString: process.env.DATABASE_URL });

// ✅ CORRECT - Per-request client
import { cache } from "react";
import { Pool } from "pg";

export const getDb = cache(() => {
  const pool = new Pool({
    connectionString: process.env.DATABASE_URL,
    maxUses: 1,  // Don't reuse connections across requests
  });
  return drizzle({ client: pool, schema });
});

// Usage in route
export async function GET() {
  const db = getDb();
  const users = await db.select().from(usersTable);
  return Response.json(users);
}

Drizzle と Prisma のパターンについては、references/database-orm.md を参照してください。

重要なルール

✅ 使う
  1. Node.js ランタイムを使う - デフォルトのランタイムです。export const runtime = "edge"は削除します。
  2. リクエストごとに DB クライアントを作成する - React の cache()を使い、リクエストスコープのインスタンスを作成します。
  3. nodejs_compat を有効にする - date >= 2024-09-23の互換性フラグが必要です。
  4. getCloudflareContext() を使う - バインディングへのアクセスには、next-on-pages の getRequestContext ではなくこちらを使います。
  5. .open-next を .gitignore に追加する - ビルド出力はコミットしないでください。
  6. wrangler.jsonc を使う - wrangler.toml ではありません(JSONC はコメントと検証に対応しています)。
  7. WORKER_SELF_REFERENCE を設定する - サービスバインディングはワーカー名と一致させる必要があります。
  8. public/_headers を追加する - 静的アセットのキャッシュヘッダーを設定します。
❌ 使わない
  1. Edge ランタイムを使わない - すべてのルートから export const runtime = "edge"を削除します。
  2. Turbopack を使わない - next build --turboではなく、next buildを使います。
  3. グローバル DB クライアントを作成しない - 「Cannot perform I/O」エラーの原因になります。
  4. 10 MiB を超えない - ワーカーのサイズ制限です(無料プランでは 3 MiB)。
  5. next-on-pages を使わない - 別のアダプターです。代わりに @opennextjs/cloudflare を使います。
  6. .open-next/ をコミットしない - ビルド出力ディレクトリです。
  7. Node Middleware を使わない - サポートされていません(Next.js 15.2 以降の機能)。

サポートされる機能

機能サポート備考
App Router✅ 完全対応すべての機能に対応
Pages Router✅ 完全対応API ルートを含む
Route Handlers✅ 完全対応GET、POST など
Dynamic Routes✅ 完全対応[slug]、[...slug]
SSG✅ 完全対応静的サイト生成
SSR✅ 完全対応サーバーサイドレンダリング
ISR✅ 完全対応インクリメンタル静的再生成
PPR✅ 完全対応部分的プリレンダリング
Middleware✅ 一部対応標準のミドルウェアには対応していますが、Node Middleware(15.2 以降)には対応していません
Image Optimization✅ 完全対応Cloudflare Images バインディング経由
Composable Caching✅ 完全対応'use cache'ディレクティブ
next/font✅ 完全対応フォントの最適化
after()✅ 完全対応バックグラウンドタスク
Turbopack❌ 非対応標準のビルドを使ってください

サポートされる Next.js のバージョン:

  • Next.js 15:すべてのマイナーバージョンおよびパッチバージョン
  • Next.js 14:最新のマイナーバージョンのみ

開発ワークフロー

# Local development with Next.js dev server
npm run dev

# Preview in Workers runtime (faster than deploy)
npm run preview

# Deploy to production
npm run deploy

# Update TypeScript types after binding changes
npm run cf-typegen

ローカル開発に関する注意:

  • next dev - Node.js ランタイムを使用します。バインディングは initOpenNextCloudflareForDev()経由で利用できます。
  • npm run preview - Wrangler を使用して Workers ランタイムを実行します。本番環境に近い動作です。
  • どちらもホットリロードに対応しています。

詳細なリファレンス

@cloudflare/next-on-pages からの移行

@cloudflare/next-on-pagesから移行する場合:

  1. @cloudflare/next-on-pagesとeslint-plugin-next-on-pagesをアンインストールします。
  2. @opennextjs/cloudflareをインストールします。
  3. next.config.tsを更新します:
    • setupDevPlatform()の呼び出しを削除します。
    • initOpenNextCloudflareForDev()に置き換えます。
  4. インポートを更新します:
    • @cloudflare/next-on-pagesのgetRequestContextを置き換えます。
    • @opennextjs/cloudflareのgetCloudflareContextを使います。
  5. Edge ランタイムのエクスポート(export const runtime = "edge")を削除します。
  6. 必須の OpenNext 設定を使って wrangler.jsonc を更新します。
  7. next-on-pages の ESLint ルールを削除します。

例

公式の例は@opennextjs/cloudflare リポジトリにあります:

  • create-next-app - Next.js の基本スターター
  • middleware - ミドルウェアの使用例
  • vercel-blog-starter - SSG ブログの例

ベストプラクティス

  1. シンプルに始める - SSG のみのサイトには Static Assets キャッシュを使用します
  2. キャッシュを段階的に追加する - ISR が必要になったら R2 キャッシュを有効にします
  3. バンドルサイズを監視する - 圧縮後 10 MiB 未満に保ちます(ESBuild Bundle Analyzer を使用します)
  4. TypeScript を使用する - cf-typegen を実行してバインディングの型を取得します
  5. プレビューでテストする - デプロイ前に npm run preview を使用します
  6. データベースクライアントをキャッシュする - リクエストごとのインスタンスには React の cache() を使用します
  7. 可観測性を有効にする - ロギングのために wrangler.jsonc に observability を追加します
  8. ビルドにリモートバインディングを使用する - 実際のデータを使った ISR のために有効にします

一般的なパターン

references/configuration.md で、以下を含む完全な例をご覧ください:

  • 複数のハンドラー(fetch、scheduled、queue)を持つカスタム Worker
  • 環境ごとの設定(staging、production)
  • ビルド時のデータアクセスに使用するリモートバインディング

リソース

コメント