prisma-expand-contract

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Prisma Expand-and-Contract Migrations

Prisma 扩展-收缩模式数据库迁移

Safe, zero-downtime database schema changes with Prisma ORM.
借助Prisma ORM实现安全、零停机的数据库架构变更。

When to Use

适用场景

  • Renaming columns or tables in production
  • Changing column types (e.g.,
    String
    to
    Enum
    )
  • Adding non-nullable columns to tables with existing data
  • Splitting or merging tables
  • Any schema change that could break running instances during deployment
  • 生产环境中重命名字段或表
  • 修改字段类型(例如:
    String
    转为
    Enum
  • 向已有数据的表添加非空字段
  • 拆分或合并表
  • 任何可能在部署期间导致运行中实例崩溃的架构变更

The Pattern

模式说明

Split destructive changes into three phases across multiple deployments:
EXPAND              MIGRATE             CONTRACT
Add new structure → Copy data,       → Remove old structure
                    update code
    Deploy 1          Deploy 2            Deploy 3
Why: During deployment, old and new application versions run simultaneously. Direct renames or type changes break old instances immediately.
将破坏性变更拆分为跨多次部署的三个阶段:
EXPAND              MIGRATE             CONTRACT
Add new structure → Copy data,       → Remove old structure
                    update code
    Deploy 1          Deploy 2            Deploy 3
原因: 部署期间,新旧版本的应用会同时运行。直接重命名或修改类型会立即导致旧版本实例崩溃。

Core Principles

核心原则

  1. Never remove in the same deploy as you add - Old code must continue working
  2. Make changes additive first - Add new columns/tables before removing old
  3. Code handles both states - During transition, read from new, write to both
  4. Data migration between deploys - Not during schema migration
  5. Cleanup is separate - Remove old structures only after all code uses new
  1. 请勿在添加新结构的同一部署中移除旧结构 - 旧代码必须能继续正常运行
  2. 优先进行增量变更 - 在移除旧字段/表之前先添加新的
  3. 代码需兼容两种状态 - 过渡期间,从新结构读取数据,同时向新旧结构写入数据
  4. 数据迁移需在部署间隙完成 - 不要在架构迁移过程中进行数据迁移
  5. 清理操作单独进行 - 仅当所有代码都已切换到新结构后,再移除旧结构

Prisma Tools for Renames

Prisma 重命名工具

@map (Column-Level)

@map(字段级)

Maps Prisma field to different database column:
prisma
model User {
  displayName String @map("user_name") // Prisma: displayName, DB: user_name
}
将Prisma模型字段映射到数据库中的不同字段:
prisma
model User {
  displayName String @map("user_name") // Prisma: displayName, 数据库: user_name
}

@@map (Table-Level)

@@map(表级)

Maps Prisma model to different database table:
prisma
model Account {
  id String @id
  @@map("users") // Prisma: Account, DB: users
}
Note:
@map
/
@@map
only work for code-level renames. For actual data migration, use full expand-and-contract.
将Prisma模型映射到数据库中的不同表:
prisma
model Account {
  id String @id
  @@map("users") // Prisma: Account, 数据库: users
}
注意:
@map
/
@@map
仅适用于代码层面的重命名。如需实际的数据迁移,请使用完整的扩展-收缩模式。

@default (Safe Non-Nullable Addition)

@default(安全添加非空字段)

For new columns where a default makes sense:
prisma
model User {
  createdAt DateTime @default(now())  // Safe to add directly
  isActive  Boolean  @default(true)   // Safe to add directly
}
对于可以设置默认值的新字段:
prisma
model User {
  createdAt DateTime @default(now())  // 可直接安全添加
  isActive  Boolean  @default(true)   // 可直接安全添加
}

Common Scenarios

常见场景

ScenarioApproach
Rename columnAdd new → backfill → make required → remove old
Change type (String→Enum)Add enum column → backfill mapping → switch reads → remove string
Add non-nullable columnAdd nullable → backfill → make required
Rename tableCreate new table → copy data → migrate code → drop old
Split tableAdd related table → copy data → update code → remove old fields
For detailed step-by-step implementations, see SCENARIOS.md.
场景实现方法
重命名字段添加新字段 → 回填数据 → 设置为必填 → 移除旧字段
类型变更(String→Enum)添加枚举字段 → 回填映射数据 → 切换读取源 → 移除原字符串字段
添加非空字段添加可空字段 → 回填数据 → 设置为必填
重命名表创建新表 → 复制数据 → 迁移代码 → 删除旧表
拆分表添加关联表 → 复制数据 → 更新代码 → 移除旧字段
如需详细的分步实现指南,请查看 SCENARIOS.md

Anti-Patterns

反模式

Direct Column Rename

直接重命名字段

prisma
// DON'T: Breaks running instances immediately
model User {
  displayName String // Was: userName
}
prisma
// 请勿这样做:会立即导致运行中实例崩溃
model User {
  displayName String // 原字段: userName
}

Remove and Add in Same Migration

同一迁移中移除并添加字段

prisma
// DON'T: Old code fails during deployment
model User {
  // Removed: userName
  displayName String // Added
}
prisma
// 请勿这样做:部署期间旧代码会失效
model User {
  // 已移除: userName
  displayName String // 新增字段
}

migrate dev in Production

在生产环境中使用 migrate dev

bash
undefined
bash
// 请勿这样做:可能导致数据丢失
npx prisma migrate dev

// 正确做法:使用 migrate deploy
npx prisma migrate deploy

DON'T: Can cause data loss

未回填数据就设置为非空

npx prisma migrate dev
prisma
// 请勿这样做:如果存在空值,迁移会失败
model User {
  email String // 原类型为 String?
}

DO: Use migrate deploy

快速参考

npx prisma migrate deploy
undefined
bash
npx prisma migrate dev --name name    # 开发环境:创建并应用迁移
npx prisma migrate deploy             # 生产环境:应用待处理的迁移
npx prisma migrate status             # 查看迁移状态
如需部署检查清单和回滚策略,请查看 CHECKLISTS.md

Non-Nullable Without Backfill

额外资源

prisma
// DON'T: Migration fails if nulls exist
model User {
  email String // Changed from String?
}

Quick Reference

bash
npx prisma migrate dev --name name    # Development: create + apply
npx prisma migrate deploy             # Production: apply pending
npx prisma migrate status             # View migration status
For deployment checklists and rollback strategies, see CHECKLISTS.md.

Additional Resources