生产环境部署:migrate deploy 与 CI/CD 集成
migrate dev vs migrate deploy
开发环境用 migrate dev,生产环境只用 migrate deploy。
| migrate dev | migrate deploy | |
|---|---|---|
| 目的 | 生成新迁移 + 应用 | 只应用已有的迁移 |
| 能否连接开发数据库 | ✅ 是 | 可以,但没必要 |
| 能否连接生产数据库 | ⚠️ 不推荐 | ✅ 应该 |
| 会读取 Schema 吗 | ✅ 会(对比差异生成新迁移) | ❌ 不会(只看 migrations/ 目录) |
| 会改数据库结构吗 | 生成 + 应用 | 只应用未执行的 |
migrate dev 不应该连接生产数据库——它有能力根据 Schema 变化生成新迁移并直接执行,而你不希望它在生产环境生成和应用新 SQL。生产数据库应该只执行 migrations/ 目录里已经在开发环境审阅和测试过的迁移文件。
标准生产部署流程
1. 开发环境:改 Schema → migrate dev --name xxx → git commit migrations/
2. CI 环境:拉代码 → npm ci → 运行 migrate deploy → 跑测试
3. 生产环境:拉代码 → npm ci → 运行 migrate deploy → 重启应用
迁移文件跟着代码一起提交到 Git。部署时只需要在应用启动前(或同时)执行 migrate deploy。
Vercel 部署示例
在 Vercel 的项目设置里:
- Build Command:保持默认(Next.js 通常是
next build) - Output Directory:
.next - Pre-build Command(或在 Build Command 里加):
npx prisma migrate deploy
或者在 Next.js 的 API Route 或 Middleware 里做启动时检查:
// src/lib/ensure-db.ts
// 服务器启动前跑一次
await prisma.$connect()
// 也可以自动部署迁移:
// await prisma.$migrate.deploy() // 内部就是 migrate deploy
注意 Vercel 的 Serverless Functions 是无状态的、可能被并行调用。不要在每个函数实例启动时都跑 migrate deploy——应该通过 Vercel 的 Pre-build Command 或单独的 CI/CD 步骤执行一次。
Docker 部署
# Dockerfile 片段
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npx prisma generate
RUN npm run build
# 生产环境容器启动时
CMD ["sh", "-c", "npx prisma migrate deploy && npm start"]
--schema 参数指定路径
如果你的 schema.prisma 不在默认位置:
npx prisma migrate deploy --schema=./path/to/schema.prisma
迁移版本控制
migrate deploy 怎么知道哪些迁移已经应用过了?它在数据库里维护一张表 _prisma_migrations:
| 字段 | 含义 |
|---|---|
| migration_name | 迁移目录名 |
| finished_at | 完成时间 |
| rolled_back_at | 如果回滚了,回滚时间 |
| started_at | 开始时间 |
| checksum | migration.sql 的 hash(防篡改) |
每次 migrate deploy 都会:
- 列出
migrations/目录下的所有迁移 - 对比
_prisma_migrations表,找出未应用的 - 按顺序执行,一个成功才下一个
如果某个迁移执行失败,后面的都不会执行,已执行的不会回滚(这与 Prisma 7 的"每个迁移独立事务"有关)。
部署前验证
npx prisma migrate status --env=production
确认生产数据库的迁移历史与本地一致、没有 pending 未应用的迁移再部署。