> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vibestrap.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# 部署到 Cloudflare Workers

> 从 Vercel 迁到 Workers，拿到亚 50ms 全球延迟。

当 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 部署](/zh/deployment/vercel)。

仓库根目录有 `wrangler.toml.example`——复制它，别从零写。

## 步骤

### 1. 装 OpenNext Cloudflare adapter

```bash theme={null}
pnpm add -D @opennextjs/cloudflare
```

它把 Next.js app 打成 Worker 兼容的 bundle，放到 `.open-next/worker.js`。

### 2. 建 wrangler.toml

```bash theme={null}
cp wrangler.toml.example wrangler.toml
```

改两处：

* `name` —— 你的 Worker 名字（小写、连字符）。
* `account_id` —— 取消注释，贴你的 Cloudflare account id。

预置文件已经设了 `compatibility_date`、`nodejs_compat` flag、`.open-next/assets` binding 和
`[assets]` 块。除非你清楚为什么，否则别改。

### 3. 换 serverless 友好的 DB pooler

Workers 跑几毫秒就销毁——经典 `pg` 驱动在 cold start 上死。挑一个：

```
# Neon —— 走 HTTP，不需要连接池
DATABASE_URL=postgresql://user:pass@ep-xyz.neon.tech/db?sslmode=require

# Supabase —— pgbouncer transaction mode（6543 端口）
DATABASE_URL=postgresql://user:pass@db.xyz.supabase.co:6543/postgres?pgbouncer=true
```

如果你继续用 Drizzle（脚手架里只有这一个 ORM，所以是的），可能需要把 `src/db/index.ts` 的
驱动换成 `drizzle-orm/neon-http` 或配置成 pooled 模式的 `drizzle-orm/postgres-js`。
`pg` 驱动在 Workers 上跑不起来。

### 4. 用 wrangler 推 secrets

**永远不要**把 secrets 提交到 `wrangler.toml`。逐个推：

```bash theme={null}
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 并部署

```bash theme={null}
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 `fs`、`child_process`、
  `net`、`worker_threads` 的库都会无声坏。脚手架本体干净——风险在你加的第三方库。
* **KV 一致性误解。** Workers KV 是**最终一致**。别拿它当 auth session 或 payment 幂等性的真相
  来源。账目类的真相来源永远是 Postgres。
* **`vars` 和 `secrets` 混了。** `[vars]` 是公开的（进 source）。`wrangler secret put` 是加密的。
  把 `STRIPE_SECRET_KEY` 放 `[vars]` 是会清空你钱包的错。
* **部署大小限制。** Workers 免费套餐 1 MB（压缩后）。OpenNext 很快撞顶——上线带图或字体的东西
  之前升 Paid（\$5/月，10 MB）。

## 官方文档

* Cloudflare Workers：[developers.cloudflare.com/workers](https://developers.cloudflare.com/workers/)
* OpenNext Cloudflare adapter：[opennext.js.org/cloudflare](https://opennext.js.org/cloudflare)
* Wrangler CLI 参考：[developers.cloudflare.com/workers/wrangler](https://developers.cloudflare.com/workers/wrangler/)
* Neon serverless driver：[neon.tech/docs/serverless/serverless-driver](https://neon.tech/docs/serverless/serverless-driver)
* Supabase pgbouncer：[supabase.com/docs/guides/database/connecting-to-postgres#connection-pooler](https://supabase.com/docs/guides/database/connecting-to-postgres#connection-pooler)
