关于 cloudflare-opennext
Cloudflare OpenNext 是将 Next.js 应用部署到 Cloudflare Workers 的适配器与技能,适合新建部署或迁移应用的开发者。它支持 App Router、Pages Router、ISR、SSG 及 Cloudflare 绑定,并提供构建和预览命令。
主要功能
- 01将 Next.js 构建输出转换为 Workers
- 02支持 App Router 与 Pages Router
- 03支持 SSG、SSR 和 ISR
- 04接入 Cloudflare 绑定
- 05提供构建、预览和部署命令
适用场景
- 01将新建的 Next.js 应用部署到 Workers
- 02把现有 Next.js 应用迁移至 Cloudflare
- 03为 ISR 或 SSG 配置缓存
- 04在路由中使用 Cloudflare 绑定
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ null-shot/ cloudflare-skills --skill cloudflare-opennext安装后在 Claude Code 中输入/cloudflare-opennext确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/caching.mdconfiguration.mddatabase-orm.mdtroubleshooting.md详细介绍
Cloudflare OpenNext
使用 @opennextjs/cloudflare 适配器将 Next.js 应用部署到 Cloudflare Workers,全面支持 App Router、Pages Router、ISR、SSG 和 Cloudflare 绑定。
适用场景
- 为 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 适配器:
- 运行
next build以生成 Next.js 构建输出 - 转换构建输出,使其能够在 Cloudflare Workers 运行时中工作
- 将输出写入
.open-next/目录,入口文件为worker.js - 使用 Workers Static Assets 提供静态文件(
_next/static、public)
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-23WORKER_SELF_REFERENCE服务绑定(必须与 Worker 名称一致)- 不应更改
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.developmentproduction→.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 为 Wrangler 封装了 OpenNext 专属行为:
# 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、内存 |
| 标签缓存 | 按需重新验证 | 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。
重要规则
✅ 应该做
- 使用 Node.js 运行时 - 默认运行时,移除任何
export const runtime = "edge" - 为每个请求创建数据库客户端 - 使用 React 的
cache()创建请求范围的实例 - 启用 nodejs_compat - 必需的兼容性标志,且日期须为 2024-09-23 或之后
- 使用 getCloudflareContext() - 访问绑定,不要使用 next-on-pages 中的 getRequestContext
- 将 .open-next 添加到 .gitignore - 不应提交构建输出
- 使用 wrangler.jsonc - 不要使用 wrangler.toml(JSONC 支持注释和验证)
- 设置 WORKER_SELF_REFERENCE - 服务绑定必须与 Worker 名称一致
- 添加 public/_headers - 配置静态资源缓存标头
❌ 不要做
- 不要使用 Edge 运行时 - 从所有路由中移除
export const runtime = "edge" - 不要使用 Turbopack - 使用
next build,不要使用next build --turbo - 不要创建全局数据库客户端 - 会导致 “Cannot perform I/O” 错误
- 不要超过 10 MiB - Worker 大小限制(免费套餐为 3 MiB)
- 不要使用 next-on-pages - 这是不同的适配器,请改用 @opennextjs/cloudflare
- 不要提交 .open-next/ - 这是构建输出目录
- 不要使用 Node 中间件 - 不受支持(Next.js 15.2+ 功能)
支持的功能
| 功能 | 支持情况 | 备注 |
|---|---|---|
| App Router | ✅ 完全支持 | 支持所有功能 |
| Pages Router | ✅ 完全支持 | 包括 API 路由 |
| Route Handlers | ✅ 完全支持 | GET、POST 等 |
| 动态路由 | ✅ 完全支持 | [slug]、[...slug] |
| SSG | ✅ 完全支持 | 静态站点生成 |
| SSR | ✅ 完全支持 | 服务端渲染 |
| ISR | ✅ 完全支持 | 增量静态再生成 |
| PPR | ✅ 完全支持 | 部分预渲染 |
| Middleware | ✅ 部分支持 | 支持标准中间件,不支持 Node 中间件(15.2+) |
| 图像优化 | ✅ 完全支持 | 通过 Cloudflare Images 绑定实现 |
| 可组合缓存 | ✅ 完全支持 | '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 运行时,更接近生产环境- 两者都支持热重载
详细参考
- references/configuration.md - 完整的 wrangler.jsonc、环境变量、TypeScript 类型
- references/caching.md - ISR、SSG、R2/KV/D1 缓存、标签缓存、队列、缓存清除
- references/database-orm.md - 使用 D1、PostgreSQL、Hyperdrive 配置 Drizzle、Prisma
- references/troubleshooting.md - 大小限制、包分析、常见错误
从 @cloudflare/next-on-pages 迁移
如果要从 @cloudflare/next-on-pages 迁移:
- 卸载
@cloudflare/next-on-pages和eslint-plugin-next-on-pages - 安装
@opennextjs/cloudflare - 更新
next.config.ts:- 移除
setupDevPlatform()调用 - 替换为
initOpenNextCloudflareForDev()
- 移除
- 更新导入:
- 移除从
@cloudflare/next-on-pages导入的getRequestContext - 使用从
@opennextjs/cloudflare导入的getCloudflareContext
- 移除从
- 移除 Edge 运行时导出(
export const runtime = "edge") - 使用必需的 OpenNext 设置更新 wrangler.jsonc
- 移除 next-on-pages eslint 规则
示例
@opennextjs/cloudflare 仓库中的官方示例:
create-next-app- 基础 Next.js 入门项目middleware- 中间件用法vercel-blog-starter- SSG 博客示例
最佳实践
- 从简单开始 - 仅限 SSG 的网站使用 Static Assets 缓存
- 逐步添加缓存 - 需要 ISR 时启用 R2 缓存
- 监控打包体积 - 保持压缩后小于 10 MiB(使用 ESBuild Bundle Analyzer)
- 使用 TypeScript - 运行
cf-typegen获取绑定类型 - 使用预览进行测试 - 部署前运行
npm run preview - 缓存数据库客户端 - 使用 React 的
cache()创建每个请求对应的实例 - 启用可观测性 - 在 wrangler.jsonc 中添加
observability以记录日志 - 使用远程绑定进行构建 - 启用此功能,以便 ISR 使用真实数据
常见模式
请参阅 references/configuration.md,了解完整示例,包括:
- 包含多个处理程序(fetch、scheduled、queue)的自定义 Worker
- 特定环境的配置(staging、production)
- 用于在构建时访问数据的远程绑定