跳转到主要内容
当 Vercel 不够用时——高流量、要全球 p99 亚 50ms 延迟,或者大规模下想压低出口流量成本—— Cloudflare Workers 是升级路径。迁移就一次 adapter 切换(OpenNext for Cloudflare)外加换一个 serverless 友好的 Postgres pooler。第一次上 Workers 留半个下午;之前发过 Worker 的话更短。

前置条件

  • 一个开通了 Workers 的 Cloudflare 账号(免费套餐够 staging)。
  • 已认证的 wrangler CLI:pnpm dlx wrangler login
  • Cloudflare account ID(dashboard 右侧栏)。
  • 一个 serverless 友好的 Postgres pooler URL——Workers 不能维持长 TCP 连接,所以直连 URL 不行。可选:Neon serverless driver(HTTP)、Supabase pgbouncer(transaction mode)、 或者自托管的 PgBouncer。
  • 你已有的 Vercel 那套环境变量值(你已经在 Vercel 上线了对吧?)。先看 Vercel 部署
仓库根目录有 wrangler.toml.example——复制它,别从零写。

步骤

1. 装 OpenNext Cloudflare adapter

pnpm add -D @opennextjs/cloudflare
它把 Next.js app 打成 Worker 兼容的 bundle,放到 .open-next/worker.js

2. 建 wrangler.toml

cp wrangler.toml.example wrangler.toml
改两处:
  • name —— 你的 Worker 名字(小写、连字符)。
  • account_id —— 取消注释,贴你的 Cloudflare account id。
预置文件已经设了 compatibility_datenodejs_compat flag、.open-next/assets binding 和 [assets] 块。除非你清楚为什么,否则别改。

3. 换 serverless 友好的 DB pooler

Workers 跑几毫秒就销毁——经典 pg 驱动在 cold start 上死。挑一个:
# Neon —— 走 HTTP,不需要连接池
DATABASE_URL=postgresql://user:[email protected]/db?sslmode=require

# Supabase —— pgbouncer transaction mode(6543 端口)
DATABASE_URL=postgresql://user:[email protected]:6543/postgres?pgbouncer=true
如果你继续用 Drizzle(脚手架里只有这一个 ORM,所以是的),可能需要把 src/db/index.ts 的 驱动换成 drizzle-orm/neon-http 或配置成 pooled 模式的 drizzle-orm/postgres-jspg 驱动在 Workers 上跑不起来。

4. 用 wrangler 推 secrets

永远不要把 secrets 提交到 wrangler.toml。逐个推:
wrangler secret put DATABASE_URL
wrangler secret put BETTER_AUTH_SECRET
wrangler secret put STRIPE_SECRET_KEY
wrangler secret put STRIPE_WEBHOOK_SECRET
wrangler secret put RESEND_API_KEY
# …用到的服务端 env 变量逐个推
公开变量(NEXT_PUBLIC_*)放 wrangler.toml[vars] 里——反正会进客户端 bundle,无所谓。

5. Build 并部署

pnpm exec opennextjs-cloudflare build
pnpm exec wrangler deploy
首次 build 慢(约 3-5 分钟),因为 OpenNext 提前打包每个页面。之后增量缓存好得多。 部署 URL 会打到 stdout——形如 https://<你的-worker-name>.<你的-子域>.workers.dev。 自定义域名走 Cloudflare dashboard(Workers & Pages → 你的 worker → Custom Domains)。

6. 重指 payment webhook

和 Vercel 一样:在支付 provider 的 dashboard 改 webhook endpoint URL 为新的 Workers 域名。 确认你 wrangler secret put 推的签名密钥和 dashboard 那边一致。

验证

清单和 Vercel 完全一样:
  • https://your-worker.workers.dev/ —— 首页正常
  • https://your-worker.workers.dev/api/ping —— { ok: true }
  • https://your-worker.workers.dev/sitemap.xml —— 有内容
  • 真实 $1 试充 → payment 行 5 秒内出现。
Workers 在 dashboard 给你 per-request CPU 时间。如果简单页面持续 > 50ms CPU, 说明 DB 驱动配错了,正在 hold 连接。

常见坑

  • 长 DB 连接。 头号错误。Workers 没法 hold 连接池——每个请求一个新 isolate,TCP socket 在 请求结束就消失。用 Neon 的 HTTP 驱动或 Supabase pgbouncer URL。症状:负载下随机 522 / 524。
  • nodejs_compat flag。 预置 config 已经有;如果你删了,webhook 签名验证(node:crypto) 在运行时炸。
  • Node-only 依赖。 部署前用 pnpm dlx knip 审一遍依赖。任何 import fschild_processnetworker_threads 的库都会无声坏。脚手架本体干净——风险在你加的第三方库。
  • KV 一致性误解。 Workers KV 是最终一致。别拿它当 auth session 或 payment 幂等性的真相 来源。账目类的真相来源永远是 Postgres。
  • varssecrets 混了。 [vars] 是公开的(进 source)。wrangler secret put 是加密的。 把 STRIPE_SECRET_KEY[vars] 是会清空你钱包的错。
  • 部署大小限制。 Workers 免费套餐 1 MB(压缩后)。OpenNext 很快撞顶——上线带图或字体的东西 之前升 Paid($5/月,10 MB)。

官方文档