git push 到上线大约 5 分钟,大头是粘 secrets 和建数据库。
前置条件
- 一个带连接池的 Postgres 数据库。Neon、Supabase、Railway、Crunchy 都行。Serverless 函数
不维持长连接,所以必须用 pooler URL(Supabase 的 6543 端口、Neon 的
-pooler主机名)。 - 一个 32 位以上的随机
BETTER_AUTH_SECRET:openssl rand -base64 32。 - 当前支付 provider 的密钥。
siteConfig.payment.provider选哪个,对应的*_SECRET_KEY、*_WEBHOOK_SECRET和相关*_PRICE_*id 就要填齐。 - 可选但建议:
RESEND_API_KEY用于事务邮件。没有的话邮件 facade 静默 no-op,注册会跳过验证步骤。 - Vercel 能读到的 GitHub 仓库。SSO、monorepo、fork 都行。
pnpm typecheck && pnpm lint && pnpm build。CI 会跑同样三条;
Vercel 也会在同一关卡拒掉坏 build。
步骤
1. Push 到 GitHub
2. 在 Vercel 导入
Vercel dashboard:Add New → Project → 选仓库。Framework Preset 自动识别为 Next.js。 build command 留空(Vercel 从package.json 读 pnpm build)。Output directory 是 .next(默认)。
3. 填环境变量
Settings → Environment Variables。必填基线:RESEND_API_KEY、GOOGLE_CLIENT_ID/SECRET、TURNSTILE_SECRET_KEY +
NEXT_PUBLIC_TURNSTILE_SITE_KEY。完整清单见 Env 参考。
4. 同步生产数据库
首次部署前先把 schema 同步过去。两种方式:db:push——它会无声丢列。改用方案 B,从 deploy hook
或一次性脚本跑 db:migrate,别从运行中的 app 跑。
5. 配置支付 webhook
在支付 provider 的 dashboard,加 webhook endpoint,指向:checkout.session.completed、invoice.paid、
customer.subscription.updated、customer.subscription.deleted(Stripe 命名——
其他 provider 自行对应)。把签名密钥贴回 STRIPE_WEBHOOK_SECRET(或对应变量)。
6. Deploy
push 或点 Deploy。首次 build 2-3 分钟。Vercel 的日志会大声报 env 错误——src/env.ts 会在
启动时对必填项缺失抛错。
验证
逐个访问下面的 URL,红的就是哪里没配好。https://your-domain.com/—— 首页正常,hero 是你设的语言https://your-domain.com/zh/—— 中文 herohttps://your-domain.com/api/ping—— 返回{ ok: true }https://your-domain.com/sitemap.xml—— 所有公共路由都列出来https://your-domain.com/robots.txt——/admin、/api/、/settings全 disallowhttps://your-domain.com/register—— 注册可用,能收到验证邮件
payment 和 credit_transaction 两张
表应该在结账后 5 秒内各出现一行。如果没出现,去支付 dashboard 的 webhook 日志看 4xx 响应。
常见坑
BETTER_AUTH_URL不一致。 必须是带 scheme 的完整 prod URL,不带末尾斜杠。和实际域名 漂移时认证回调会静默失败。- prod 缺环境变量。 Vercel 把 Production / Preview / Development 分开。除非你刻意要分环境 值,否则统一勾「All Environments」。
- Webhook 签名密钥不对。 旧的
STRIPE_WEBHOOK_SECRET会让每个事件返回 400。在 dashboard 轮换一次密钥,贴回 Vercel,重新部署。 - Postgres 连接数撑满。 Serverless 函数烧连接很快。用 pooler URL(Supabase 6543 端口、
Neon 的
-pooler.region主机)。撞「max connections」?你用的是直连 URL。 - 忘了
NEXT_PUBLIC_APP_URL。 被 sitemap、OG 图、OAuth redirect、支付成功 URL 用。 生产环境必须和BETTER_AUTH_URL一致。 - 首次部署前没跑
db:push。 App 起得来,第一个 query 就 500,因为表不存在。
回滚
Vercel 永久保留每次部署。从 Deployments 列表把任意旧 build promote 回去——秒级回滚。 如果是 migration 的锅,用 DB provider 的 point-in-time 快照恢复(Neon 和 Supabase 所有套餐 都自带)。官方文档
- Vercel Next.js 指南:vercel.com/docs/frameworks/nextjs
- Env 变量:vercel.com/docs/projects/environment-variables
- Cron jobs(用于积分过期清扫):vercel.com/docs/cron-jobs
- Drizzle migration:orm.drizzle.team/docs/migrations