迁移Cloudflare Pages到Workers:Next.js全栈开发新选择
将 Next.js 从 Pages(next-on-pages)迁移到基于 Workers 的 opennextjs 项目,以解锁 Node.js 运行时、ISR、PPR 等最新能力。

为什么选择 OpenNext.js/Cloudflare?
过去,我们使用 Next.js 结合 Cloudflare Pages 进行全栈开发,因为这是 Cloudflare 官方推荐的方案。然而,Cloudflare Pages 更适合静态网站,而 Next.js 的最新功能(如 ISR、PPR)需要 Node.js 兼容环境。Cloudflare 近期宣布 OpenNext.js/Cloudflare GA,推荐 Pages 用户迁移到 Workers,以充分发挥 Next.js 的能力。

迁移的好处
支持最新功能:在 Cloudflare Workers 的 Node.js 环境中运行,解锁 Next.js 的 ISR、PPR 等功能。
更灵活的运行时:OpenNext.js/Cloudflare 是一个适配器,允许 Next.js 应用运行在 Node.js 环境中,而非 Pages 的 Edge 环境。
优化的缓存机制:通过 R2 或 KV 存储支持高效缓存,提升性能。
前提条件
Next.js 运行环境:OpenNext.js/Cloudflare 仅支持 Node.js 运行时,不支持 Edge 运行时。
Next.js 版本:支持 Next.js 14 和 15。
迁移步骤
以下是详细的迁移步骤,助你从 Cloudflare Pages 顺利切换到 OpenNext.js/Cloudflare:
安装依赖
npm install @opennextjs/cloudflare@latest
npm install --save-dev wrangler@latest创建 wrangler.jsonc(可选)
若不创建,@opennextjs/cloudflare 会自动生成默认配置文件。但如果你需要自定义(如支持 D1、R2 或 preview 模式),则需要创建。
项目根目录新建 wrangler.jsonc:
{
"$schema": "node_modules/wrangler/config-schema.json",
"main": ".open-next/worker.js",
"name": "<APP-NAME>",
"compatibility_date": "2024-12-30",
"compatibility_flags": [
"nodejs_compat", // 启用 Node.js API
"global_fetch_strictly_public" // 放宽 fetch 限制
],
"assets": {
"directory": ".open-next/assets",
"binding": "ASSETS"
},
"services": [
{
"binding": "WORKER_SELF_REFERENCE",
"service": "<APP-NAME>" // 必须与上面的 name 一致
}
],
"r2_buckets": [
// 示例 R2 绑定
// {
// "binding": "NEXT_INC_CACHE_R2_BUCKET",
// "bucket_name": "<BUCKET_NAME>"
// }
]
}compatibility_date必填,并且日期要 ≥ 2024-09-23。main指向构建产物.open-next/worker.js。
创建 open-next.config.ts(可选)
若不创建,opennextjs-cloudflare build 会生成默认配置。建议在项目根目录创建 open-next.config.ts:
// open-next.config.ts
import { defineCloudflareConfig } from "@opennextjs/cloudflare";
import r2IncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache";
export default defineCloudflareConfig({
// 基础启用 R2 增量缓存(最简)
incrementalCache: r2IncrementalCache,
});新增 .dev.vars
用于支持 wrangler dev、opennextjs-cloudflare dev 和 preview 模式。在项目根目录创建 .dev.vars:
NEXTJS_ENV=development更新 package.json 脚本
{
"scripts": {
"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"
}
}build:必须执行next build(被opennextjs-cloudflare build调用)。preview:本地启动模拟 Workers 的环境进行预览。deploy:构建并部署到 Workers。upload:构建并上传新版本到 Workers(不切流)。cf-typegen:生成cloudflare-env.d.ts以获得绑定类型提示。
静态资源长缓存
在 public/_headers:
/_next/static/*
Cache-Control: public,max-age=31536000,immutable切换到 Node.js 运行时
全局移除:
export const runtime = "edge";
Git忽略构建中间文件
# .gitignore
.open-next移除 Cloudflare Pages 相关依赖
卸载依赖:
@cloudflare/next-on-pages、eslint-plugin-next-on-pages。从
next.config.*移除setupDevPlatform()。API 替换:
getRequestContext→getCloudflareContext(来自@opennextjs/cloudflare)。
缓存架构(ISR/PPR/缓存更新)
Serverless 环境进程短暂、无持久文件系统,需使用外部服务实现 Next.js 缓存能力。@opennextjs/cloudflare 需要:
Incremental Cache:存放增量页面/数据缓存(R2 或 KV)。
Queue:同步和去重基于时间的重新验证。
Tag Cache:支持
revalidateTag/revalidatePath的按需重新验证。
选择存储后端
R2(对象存储):一致性强,跨区域表现稳定,适合长期缓存。
KV(类 Redis):读写快、延迟低;但多区域同步存在 ~60s 的一致性窗口。
R2 缓存配置示例
open-next.config.ts:
import { defineCloudflareConfig } from "@opennextjs/cloudflare";
import r2IncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache";
import { withRegionalCache } from "@opennextjs/cloudflare/overrides/incremental-cache/regional-cache";
import doQueue from "@opennextjs/cloudflare/overrides/queue/do-queue";
import queueCache from "@opennextjs/cloudflare/overrides/queue/queue-cache";
import doShardedTagCache from "@opennextjs/cloudflare/overrides/tag-cache/do-sharded-tag-cache";
export default defineCloudflareConfig({
incrementalCache: withRegionalCache(r2IncrementalCache, {
mode: "long-lived",
}),
tagCache: doShardedTagCache({ baseShardSize: 12, regionalCache: true }),
queue: queueCache(doQueue, {
regionalCacheTtlSec: 5,
waitForQueueAck: true,
}),
});wrangler.jsonc 绑定:
{
"r2_buckets": [
{ "binding": "NEXT_INC_CACHE_R2_BUCKET", "bucket_name": "<YOUR-R2-BUCKET>" }
],
"durable_objects": {
"bindings": [
{ "name": "NEXT_CACHE_DO_QUEUE", "class_name": "DOQueueHandler" },
{ "name": "NEXT_TAG_CACHE_DO_SHARDED", "class_name": "DOShardedTagCache" }
]
},
"migrations": [
{ "tag": "v1", "new_sqlite_classes": ["DOQueueHandler", "DOShardedTagCache"] }
]
}DOQueueHandler 负责队列与缓存刷新;DOShardedTagCache 管理 Tag 级别的失效。KV 方案
若使用 KV,请在 wrangler.jsonc 中添加 KV 命名空间并在 open-next.config.ts 选择对应的增量缓存实现。KV 的多区域同步延迟需在业务上容忍。
构建时 vs 运行时:环境变量与绑定
运行时:
wrangler.jsonc中的 bindings(R2、KV、D1、DO 等)在 Workers 运行时可用。构建时:Next.js 构建阶段无法直接访问这些 bindings。
绕过方式:
将必须在构建期获取的数据改到 运行时(
getServerSideProps/fetch)或使用 静态占位 + 运行时 hydrate。若确需构建时访问 Cloudflare 资源,改用 Cloudflare API(通过普通 HTTP、使用 Token),而非 bindings。
本地开发与验证
预览:
bashnpm run preview部署:
bashnpm run deploy上传不切流:
bashnpm run upload类型生成:
bashnpm run cf-typegen
验证清单:
compatibility_date ≥ 2024-09-23,wrangler ≥ 3.99.0。移除
runtime = "edge"与next-on-pages依赖。wrangler.jsonc的name与services.service一致。.open-next已加入.gitignore。静态资源设置了长缓存 Header。
ISR/PPR 路由命中后,缓存命中率与再验证行为符合预期。
CI/CD(GitHub Actions 示例)
name: Deploy
on:
push:
branches: [ main ]
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
- run: npm run build
- run: npx opennextjs-cloudflare build
- run: npx opennextjs-cloudflare upload
- if: github.ref == 'refs/heads/main'
run: npx opennextjs-cloudflare deploy
env:
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}预览/分支环境可用 preview,或为每个分支设置独立的 name 与 R2/KV 命名空间。
常见坑与排查
版本/日期不满足:
compatibility_date未设置或早于 2024-09-23,或 wrangler < 3.99.0。运行时不一致:仍残留
runtime = "edge"导致 Node 特性不可用。自引用 service 未对齐:
services.service与name不一致导致内部 fetch 失败。未配置缓存后端:未设置 R2/KV 造成 ISR 退化为 SSR,性能下降。
区域一致性差异(KV):跨区域读到旧数据,需调整 TTL 或切换 R2。
清理不彻底:
setupDevPlatform()未移除、getRequestContext未替换为getCloudflareContext。构建期读取绑定:请改为运行时或走 Cloudflare API。
FAQ
Q: 能否部分路由用 Edge、部分用 Node? A: 本适配器仅支持 Node.js 运行时;如需 Edge Middlewares,请权衡并将核心渲染留在 Node。
Q: ISR 失败如何定位?
A: 打开 DO/Queue 日志,确认 DOQueueHandler 是否收到任务;检查 R2 权限与绑定;确认 tagCache 是否正确初始化。
Q: 如何做按区域就近缓存?
A: 使用 withRegionalCache(...),并控制 regionalCacheTtlSec 与一致性策略。
迁移回滚策略
保留
Pages + next-on-pages的最后一次可用部署作为回滚目标。Workers 新版本 先
upload后deploy,灰度验证通过再切流。缓存层(R2/KV/DO)使用新命名空间,避免与旧环境互相污染。
最后
通过以上步骤,你可以将 Next.js 应用从 Cloudflare Pages 迁移到 OpenNext.js/Cloudflare,充分利用 Node.js 运行时和 Next.js 的最新功能。合理配置缓存(如 R2 或 KV)可显著提升性能。迁移后,你可以在本地运行 npm run preview 测试,或通过 npm run deploy 部署到 Cloudflare Workers。 如需进一步帮助,请参考 OpenNext.js 官方文档 或 Cloudflare Workers 文档。

