mcpField
C
cloudflare-nextjs

cloudflare-nextjs

github.com/jackspace云与 DevOps16116 次安装13 周前更新
代码仓库

关于 cloudflare-nextjs

使用 OpenNext Cloudflare adapter 将 Next.js 应用部署到 Cloudflare Workers 的指南 Skill。它涵盖新项目配置、现有应用迁移、开发与 workerd 预览流程、配置要求和常见部署错误。

主要功能

  1. 01OpenNext adapter 设置
  2. 02新项目与迁移指南
  3. 03Next.js 和 workerd 测试流程
  4. 04Wrangler 与 Cloudflare 绑定配置
  5. 05部署错误排查

适用场景

  1. 01将新的 Next.js 应用部署到 Cloudflare Workers
  2. 02迁移现有 Next.js 应用
  3. 03部署前测试 Workers 特有行为

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jackspace/claudeskillz --skill cloudflare-nextjs

安装后在 Claude Code 中输入/cloudflare-nextjs确认已加载。

附带文件README.mdSKILL.json

详细介绍

Cloudflare Next.js 部署技能

使用 OpenNext Cloudflare 适配器将 Next.js 应用部署到 Cloudflare Workers,实现可用于生产环境的无服务器 Next.js 托管。

适用场景

  • 将 Next.js 应用(App Router 或 Pages Router)部署到 Cloudflare Workers
  • 需要在 Cloudflare 上实现服务端渲染(SSR)、静态站点生成(SSG)或增量静态再生成(ISR)
  • 将现有 Next.js 应用从 Vercel、AWS 或其他平台迁移到 Cloudflare
  • 使用 Cloudflare 服务(D1、R2、KV、Workers AI)构建全栈 Next.js 应用
  • 需要在 Workers 上使用 React Server Components、Server Actions 或 Next.js 中间件
  • 希望通过 Cloudflare 的网络实现全球边缘部署

核心概念

OpenNext 适配器架构

OpenNext Cloudflare 适配器(@opennextjs/cloudflare)会将 Next.js 构建产物转换为兼容 Cloudflare Worker 的格式。这与标准 Next.js 部署方式有本质区别:

  • 需要 Node.js 运行时:在 Workers 中使用 Node.js 运行时(而非 Edge 运行时)
  • 双重开发工作流:同时在 Next.js 开发服务器和 workerd 运行时中测试
  • 自定义构建流程:next build → OpenNext 转换 → Worker 部署
  • Cloudflare 专属配置:需要 wrangler.jsonc 和 open-next.config.ts
与标准 Next.js 的关键区别
方面标准 Next.jsCloudflare Workers
运行时Node.js 或 EdgeNode.js(通过 nodejs_compat)
开发服务器next devnext dev + opennextjs-cloudflare preview
部署取决于平台opennextjs-cloudflare deploy
Worker 大小无限制3 MiB(免费)/ 10 MiB(付费)
数据库连接可使用全局客户端必须限定在请求范围内
图像优化内置通过 Cloudflare Images 实现
缓存Next.js 缓存OpenNext 配置 + Workers 缓存

设置模式

新项目设置

使用 Cloudflare 的 create-cloudflare(C3)CLI 创建新 Next.js 项目,并预先配置 Workers:

npm create cloudflare@latest -- my-next-app --framework=next

执行内容:

  1. 运行 Next.js 官方设置工具(create-next-app)
  2. 安装 @opennextjs/cloudflare 适配器
  3. 创建配置正确的 wrangler.jsonc
  4. 创建用于缓存配置的 open-next.config.ts
  5. 向 package.json 添加部署脚本
  6. 可选择立即部署到 Cloudflare

开发工作流:

npm run dev      # Next.js dev server (fast reloads)
npm run preview  # Test in workerd runtime (production-like)
npm run deploy   # Build and deploy to Cloudflare
迁移现有项目

要向现有 Next.js 应用添加 OpenNext 适配器:

1. 安装适配器
npm install --save-dev @opennextjs/cloudflare
2. 创建 wrangler.jsonc
{
  "name": "my-next-app",
  "compatibility_date": "2025-05-05",
  "compatibility_flags": ["nodejs_compat"]
}

关键配置:

  • compatibility_date:最低为 2025-05-05(用于支持 FinalizationRegistry)
  • compatibility_flags:必须包含 nodejs_compat(用于 Node.js 运行时)
3. 创建 open-next.config.ts
import { defineCloudflareConfig } from "@opennextjs/cloudflare";

export default defineCloudflareConfig({
  // Caching configuration (optional)
  // See: https://opennext.js.org/cloudflare/caching
});
4. 更新 package.json 脚本
{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "preview": "opennextjs-cloudflare build && opennextjs-cloudflare preview",
    "deploy": "opennextjs-cloudflare build && opennextjs-cloudflare deploy",
    "cf-typegen": "wrangler types --env-interface CloudflareEnv cloudflare-env.d.ts"
  }
}

脚本用途:

  • dev:Next.js 开发服务器(快速迭代)
  • preview:构建并在 workerd 运行时中运行(部署前测试)
  • deploy:构建并部署到 Cloudflare
  • cf-typegen:为 Cloudflare 绑定生成 TypeScript 类型
5. 确保使用 Node.js 运行时(而非 Edge)

从应用中移除 Edge 运行时导出:

// ❌ REMOVE THIS (Edge runtime not supported)
export const runtime = "edge";

// ✅ Use Node.js runtime (default)
// No export needed - Node.js is default

开发工作流

双重测试策略

务必在两种环境中都进行测试:

  1. Next.js 开发服务器(npm run dev)

    • 热重载速度快
    • 开发体验最佳
    • 在 Node.js 中运行(不是生产运行时)
    • 用于快速迭代
  2. Workerd 运行时(npm run preview)

    • 在接近生产的环境中运行
    • 可发现运行时特有的问题
    • 重建时间较长
    • 部署前必须运行
何时使用各环境
# Iterating on UI/logic → Use Next.js dev server
npm run dev

# Testing integrations (D1, R2, KV) → Use preview
npm run preview

# Before deploying → ALWAYS test preview
npm run preview

# Deploy to production
npm run deploy

配置要求

Wrangler 配置

wrangler.jsonc 中的最低要求:

{
  "name": "your-app-name",
  "compatibility_date": "2025-05-05",  // Minimum for FinalizationRegistry
  "compatibility_flags": ["nodejs_compat"]  // Required for Node.js runtime
}
包导出的环境变量

如果使用具有多个导出条件的 npm 包,请创建 .env:

WRANGLER_BUILD_CONDITIONS=""
WRANGLER_BUILD_PLATFORM="node"

这可确保 Wrangler 在 node 导出可用时优先使用它。

Cloudflare 绑定集成

在 wrangler.jsonc 中添加绑定:

{
  "name": "your-app-name",
  "compatibility_date": "2025-05-05",
  "compatibility_flags": ["nodejs_compat"],

  // D1 Database
  "d1_databases": [
    {
      "binding": "DB",
      "database_name": "production-db",
      "database_id": "your-database-id"
    }
  ],

  // R2 Storage
  "r2_buckets": [
    {
      "binding": "BUCKET",
      "bucket_name": "your-bucket"
    }
  ],

  // KV Storage
  "kv_namespaces": [
    {
      "binding": "KV",
      "id": "your-kv-id"
    }
  ],

  // Workers AI
  "ai": {
    "binding": "AI"
  }
}

在 Next.js 中通过 process.env 访问绑定:

// app/api/route.ts
import type { NextRequest } from 'next/server';

export async function GET(request: NextRequest) {
  // Access Cloudflare bindings
  const env = process.env as any;

  // D1 Database query
  const result = await env.DB.prepare('SELECT * FROM users').all();

  // R2 Storage access
  const file = await env.BUCKET.get('file.txt');

  // KV Storage access
  const value = await env.KV.get('key');

  // Workers AI inference
  const response = await env.AI.run('@cf/meta/llama-3-8b-instruct', {
    prompt: 'Hello AI'
  });

  return Response.json({ result });
}

错误预防(记录了 10 种以上错误)

1. 超出 Worker 大小限制(3 MiB - 免费计划)

错误:"Your Worker exceeded the size limit of 3 MiB"

原因:Workers 免费计划将 Worker 大小限制为 3 MiB(gzip 压缩后)

解决方案:

  • 升级到 Workers 付费计划(限制为 10 MiB)
  • 分析打包大小并移除未使用的依赖
  • 使用动态导入对大型依赖进行代码分割

打包分析:

npx opennextjs-cloudflare build
cd .open-next/server-functions/default
# Analyze handler.mjs.meta.json with ESBuild Bundle Analyzer

来源:https://opennext.js.org/cloudflare/troubleshooting#worker-size-limits


2. 超出 Worker 大小限制(10 MiB - 付费计划)

错误:"Your Worker exceeded the size limit of 10 MiB"

原因:不必要的代码被打包进 Worker

调试工作流:

  1. 运行 npx opennextjs-cloudflare build
  2. 前往 .open-next/server-functions/default
  3. 使用 ESBuild Bundle Analyzer 分析 handler.mjs.meta.json
  4. 找出并移除大型依赖,或将其外置

来源:https://opennext.js.org/cloudflare/troubleshooting#worker-size-limits


3. 未定义 FinalizationRegistry

错误:"ReferenceError: FinalizationRegistry is not defined"

原因:wrangler.jsonc 中的 compatibility_date 设置过早

解决方案:将 compatibility_date 更新为 2025-05-05 或更晚的日期:

{
  "compatibility_date": "2025-05-05"  // Minimum for FinalizationRegistry
}

来源:https://opennext.js.org/cloudflare/troubleshooting#finalizationregistry-is-not-defined


4. 无法代表其他请求执行 I/O

错误:"Cannot perform I/O on behalf of a different request"

原因:数据库客户端在全局范围内创建,并在多个请求间重复使用

问题代码:

// ❌ WRONG: Global DB client
import { Pool } from 'pg';
const pool = new Pool({ connectionString: process.env.DATABASE_URL });

export async function GET() {
  // This will fail - pool created in different request context
  const result = await pool.query('SELECT * FROM users');
  return Response.json(result);
}

解决方案:在请求处理程序内部创建数据库客户端:

// ✅ CORRECT: Request-scoped DB client
import { Pool } from 'pg';

export async function GET() {
  // Create client within request context
  const pool = new Pool({ connectionString: process.env.DATABASE_URL });
  const result = await pool.query('SELECT * FROM users');
  await pool.end();
  return Response.json(result);
}

替代方案:使用专为 Workers 设计的 Cloudflare D1,而不是外部数据库:

// ✅ BEST: Use D1 (no connection pooling needed)
export async function GET(request: NextRequest) {
  const env = process.env as any;
  const result = await env.DB.prepare('SELECT * FROM users').all();
  return Response.json(result);
}

来源:https://opennext.js.org/cloudflare/troubleshooting#cannot-perform-io-on-behalf-of-a-different-request


5. NPM 包导入失败

错误:"Could not resolve '<package>'"

原因:缺少 nodejs_compat 标志或包导出条件

解决方案 1:启用 nodejs_compat 标志:

{
  "compatibility_flags": ["nodejs_compat"]
}

解决方案 2:对于具有多个导出的包,创建 .env:

WRANGLER_BUILD_CONDITIONS=""
WRANGLER_BUILD_PLATFORM="node"

来源:https://opennext.js.org/cloudflare/troubleshooting#npm-packages-fail-to-import


6. 无法加载代码块(Turbopack)

错误:"Failed to load chunk server/chunks/ssr/"

原因:Next.js 使用 Turbopack 构建(next build --turbo)

解决方案:使用标准构建方式(适配器不支持 Turbopack):

{
  "scripts": {
    "build": "next build"  // ✅ Correct
    // "build": "next build --turbo"  // ❌ Don't use Turbopack
  }
}

来源:https://opennext.js.org/cloudflare/troubleshooting#failed-to-load-chunk


7. SSRF 漏洞(CVE-2025-6087)

漏洞:通过 /_next/image 端点发起的服务端请求伪造

受影响版本:@opennextjs/cloudflare < 1.3.0

解决方案:升级到 1.3.0 或更高版本:

npm install --save-dev @opennextjs/cloudflare@^1.3.0

影响:允许未经过身份验证的用户代理任意远程内容

来源:https://github.com/advisories/GHSA-rvpw-p7vw-wj3m


8. Durable Objects 绑定警告

警告:"You have defined bindings to the following internal Durable Objects... will not work in local development, but they should work in production"

原因:OpenNext 使用 Durable Objects 进行缓存(DOQueueHandler、DOShardedTagCache)

解决方案:可安全忽略——这是预期行为

替代方案(用于隐藏警告):在单独的 Worker 中定义 Durable Objects,并使用其自身配置

来源:https://opennext.js.org/cloudflare/known-issues#caching-durable-objects


9. Prisma + D1 中间件冲突

错误:在 Next.js 中间件中使用 @prisma/client + @prisma/adapter-d1 时出现构建错误

原因:在中间件上下文中初始化数据库

解决方法:在路由处理程序中初始化 Prisma 客户端,而不是在中间件中初始化

来源:https://github.com/opennextjs/opennextjs-cloudflare/issues/471


10. cross-fetch 库错误

错误:使用依赖于 cross-fetch 的库时出现错误

原因:OpenNext 会修补部署包,导致 cross-fetch 在原生 fetch 可用时尝试使用 Node.js 库

解决方案:直接使用原生 fetch API,而不是使用 cross-fetch:

// ✅ Use native fetch
const response = await fetch('https://api.example.com/data');

// ❌ Avoid cross-fetch
// import fetch from 'cross-fetch';

来源:https://opennext.js.org/cloudflare/troubleshooting


11. Windows 开发问题

问题:无法保证完全支持 Windows

原因:Next.js 底层工具在 Windows 上存在问题

解决方案:

  • 使用 WSL(适用于 Linux 的 Windows 子系统)
  • 使用 Linux 虚拟机
  • 使用基于 Linux 的 CI/CD 进行部署

来源:https://opennext.js.org/cloudflare#windows-support

功能支持矩阵

功能状态备注
App Router✅ 完全支持最新的 App Router 功能均可正常使用
Pages Router✅ 完全支持支持旧版 Pages Router
Route Handlers✅ 完全支持API 路由可按预期运行
React Server Components✅ 完全支持RSC 功能完整
Server Actions✅ 完全支持Server Actions 可正常运行
SSG✅ 完全支持静态站点生成
SSR✅ 完全支持服务端渲染
ISR✅ 完全支持增量静态再生成
Middleware✅ 支持Node.js 中间件除外(15.2+)
Image Optimization✅ 支持通过 Cloudflare Images 实现
Partial Prerendering (PPR)✅ 支持在 Next.js 中为实验性功能
Composable Caching✅ 支持'use cache' 指令
Response Streaming✅ 支持支持流式响应
next/after API✅ 支持响应后的异步工作
Node.js Middleware (15.2+)❌ 不支持计划在未来支持
Edge Runtime❌ 不支持请使用 Node.js runtime

来源:https://developers.cloudflare.com/workers/framework-guides/web-apps/nextjs/#next-js-supported-features

与 Cloudflare 服务集成

D1 数据库(SQL)
// app/api/users/route.ts
import type { NextRequest } from 'next/server';

export async function GET(request: NextRequest) {
  const env = process.env as any;

  const result = await env.DB.prepare(
    'SELECT * FROM users WHERE active = ?'
  ).bind(true).all();

  return Response.json(result.results);
}

export async function POST(request: NextRequest) {
  const env = process.env as any;
  const { name, email } = await request.json();

  const result = await env.DB.prepare(
    'INSERT INTO users (name, email) VALUES (?, ?)'
  ).bind(name, email).run();

  return Response.json({ id: result.meta.last_row_id });
}

Wrangler 配置:

{
  "d1_databases": [
    {
      "binding": "DB",
      "database_name": "production-db",
      "database_id": "your-database-id"
    }
  ]
}

另请参阅:cloudflare-d1 skill,了解完整的 D1 模式


R2 存储(对象存储)
// app/api/upload/route.ts
import type { NextRequest } from 'next/server';

export async function POST(request: NextRequest) {
  const env = process.env as any;
  const formData = await request.formData();
  const file = formData.get('file') as File;

  // Upload to R2
  await env.BUCKET.put(file.name, file.stream(), {
    httpMetadata: {
      contentType: file.type
    }
  });

  return Response.json({ success: true, filename: file.name });
}

export async function GET(request: NextRequest) {
  const env = process.env as any;
  const { searchParams } = new URL(request.url);
  const filename = searchParams.get('file');

  const object = await env.BUCKET.get(filename);
  if (!object) {
    return new Response('Not found', { status: 404 });
  }

  return new Response(object.body, {
    headers: {
      'Content-Type': object.httpMetadata?.contentType || 'application/octet-stream'
    }
  });
}

另请参阅:cloudflare-r2 skill,了解完整的 R2 模式


Workers AI(模型推理)
// app/api/ai/route.ts
import type { NextRequest } from 'next/server';

export async function POST(request: NextRequest) {
  const env = process.env as any;
  const { prompt } = await request.json();

  const response = await env.AI.run('@cf/meta/llama-3-8b-instruct', {
    prompt
  });

  return Response.json(response);
}

Wrangler 配置:

{
  "ai": {
    "binding": "AI"
  }
}

另请参阅:cloudflare-workers-ai skill,了解完整的 AI 模式


KV 存储(键值)
// app/api/cache/route.ts
import type { NextRequest } from 'next/server';

export async function GET(request: NextRequest) {
  const env = process.env as any;
  const { searchParams } = new URL(request.url);
  const key = searchParams.get('key');

  const value = await env.KV.get(key);
  return Response.json({ key, value });
}

export async function PUT(request: NextRequest) {
  const env = process.env as any;
  const { key, value, ttl } = await request.json();

  await env.KV.put(key, value, { expirationTtl: ttl });
  return Response.json({ success: true });
}

另请参阅:cloudflare-kv skill,了解完整的 KV 模式

图像优化

Next.js 图像优化通过 Cloudflare Images 实现。在 open-next.config.ts 中配置:

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

export default defineCloudflareConfig({
  imageOptimization: {
    loader: 'cloudflare'
  }
});

在组件中使用:

import Image from 'next/image';

export default function Avatar() {
  return (
    <Image
      src="/avatar.jpg"
      alt="User avatar"
      width={200}
      height={200}
      // Automatically optimized via Cloudflare Images
    />
  );
}

计费:Cloudflare Images 的使用费用单独计算

文档:https://developers.cloudflare.com/images/

缓存配置

在 open-next.config.ts 中配置缓存行为:

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

export default defineCloudflareConfig({
  // Custom cache configuration
  cache: {
    // Override default cache behavior
    // See: https://opennext.js.org/cloudflare/caching
  }
});

默认行为:OpenNext 提供合理的默认缓存设置

高级用法:请参阅 OpenNext 官方缓存文档

已知限制

尚不支持
  1. Node.js Middleware(Next.js 15.2+)

    • 在 Next.js 15.2 中引入
    • 计划在未来版本中支持
    • 目前请使用标准中间件
  2. Edge Runtime

    • 仅支持 Node.js runtime
    • 请从应用中移除 export const runtime = "edge"
  3. 完全支持 Windows

    • 无法保证在 Windows 上进行开发时一切正常
    • 请使用 WSL、VM 或基于 Linux 的 CI/CD
Worker 大小限制
  • 免费计划:限制为 3 MiB(gzip 压缩后)
  • 付费计划:限制为 10 MiB(gzip 压缩后)
  • 开发期间监控打包文件大小
  • 使用动态导入进行代码拆分
数据库连接
  • 外部数据库客户端(PostgreSQL、MySQL)必须限定在单个请求范围内
  • 不能跨请求重用连接(Workers 的限制)
  • 数据库需求优先使用 Cloudflare D1(专为 Workers 设计)

部署

从本地计算机部署
# Build and deploy in one command
npm run deploy

# Or step by step:
npx opennextjs-cloudflare build
npx opennextjs-cloudflare deploy
从 CI/CD 部署

在 CI/CD 系统中配置部署命令:

npm run deploy

示例:

  • GitHub Actions:.github/workflows/deploy.yml
  • GitLab CI:.gitlab-ci.yml
  • Cloudflare Workers Builds:自动检测 npm run deploy

环境变量:在 Cloudflare 控制面板或 CI/CD 系统中设置密钥

自定义域名

在 Cloudflare 控制面板中添加自定义域名:

  1. 导航至 Workers & Pages
  2. 选择你的 Worker
  3. Settings → Domains & Routes
  4. 添加自定义域名

DNS:域名必须托管在 Cloudflare 上(需要区域)

TypeScript 支持

为 Cloudflare 绑定生成类型:

npm run cf-typegen

此命令会创建 cloudflare-env.d.ts,其中包含绑定的类型:

// cloudflare-env.d.ts (auto-generated)
interface CloudflareEnv {
  DB: D1Database;
  BUCKET: R2Bucket;
  KV: KVNamespace;
  AI: Ai;
}

在路由处理程序中使用:

import type { NextRequest } from 'next/server';

export async function GET(request: NextRequest) {
  const env = process.env as CloudflareEnv;
  // Now env.DB, env.BUCKET, etc. are typed
}

测试

本地测试(开发环境)
# Next.js dev server (fast iteration)
npm run dev
本地测试(模拟生产环境)
# Workerd runtime (catches Workers-specific issues)
npm run preview
集成测试

部署前务必在 preview 模式下测试:

# Build and run in workerd
npm run preview

# Test bindings (D1, R2, KV, AI)
# Test middleware
# Test API routes
# Test SSR/ISR behavior

从其他平台迁移

从 Vercel 迁移
  1. 复制现有的 Next.js 项目
  2. 执行现有项目的迁移步骤(见上文)
  3. 在 Cloudflare 控制面板中更新环境变量
  4. 替换 Vercel 专属功能:
    • Vercel Postgres → Cloudflare D1
    • Vercel Blob → Cloudflare R2
    • Vercel KV → Cloudflare KV
    • Vercel Edge Config → Cloudflare KV
  5. 使用 npm run preview 进行全面测试
  6. 使用 npm run deploy 部署
从 AWS / 其他平台迁移

流程与从 Vercel 迁移相同——适配器会自动处理 Next.js 的标准功能。

资源

官方文档
故障排除
相关技能
  • cloudflare-worker-base - 使用 Hono + Vite + React 的基础 Worker 设置
  • cloudflare-d1 - D1 数据库集成
  • cloudflare-r2 - R2 对象存储
  • cloudflare-kv - KV 键值存储
  • cloudflare-workers-ai - Workers AI 集成
  • cloudflare-vectorize - 用于 RAG 的向量数据库

快速参考

基本命令
# New project
npm create cloudflare@latest -- my-next-app --framework=next

# Development
npm run dev      # Fast iteration (Next.js dev server)
npm run preview  # Test in workerd (production-like)

# Deployment
npm run deploy   # Build and deploy to Cloudflare

# TypeScript
npm run cf-typegen  # Generate binding types
关键配置
// wrangler.jsonc
{
  "compatibility_date": "2025-05-05",  // Minimum!
  "compatibility_flags": ["nodejs_compat"]  // Required!
}
常见陷阱
  1. ❌ 使用 Edge 运行时 → ✅ 使用 Node.js 运行时
  2. ❌ 全局数据库客户端 → ✅ 限定在单个请求范围内的客户端
  3. ❌ 使用过时的 compatibility_date → ✅ 使用 2025-05-05+
  4. ❌ 缺少 nodejs_compat → ✅ 添加到 compatibility_flags
  5. ❌ 只在 dev 中测试 → ✅ 部署前务必在 preview 中测试
  6. ❌ 使用 Turbopack → ✅ 使用标准 Next.js 构建

已通过生产环境测试:官方 Cloudflare 支持及活跃社区 节省 Token:相比手动设置约节省 59% 避免的错误:已记录 10+ 个问题 上次验证时间:2025-10-21

评论

支持 Markdown