<< All versions
Skill v1.0.0
currentLLM-judged scan90/100the-aios/aios/database-migration
──Details
PublishedOctober 24, 2026 at 12:48 PM
Content Hashsha256:ea1e2951e23f3db0...
Git SHAc0c91f830dbf
──Files
Files (1 file, 10.6 KB)
SKILL.md10.6 KBactive
SKILL.md · 435 lines · 10.6 KB
version: "1.0.0" name: database-migration description: Execute database migrations across ORMs and platforms with zero-downtime strategies, data transformation, and rollback procedures. Use when migrating databases, changing schemas, performing data transformations, or implementing zero-downtime deployment strategies.
Database Migration
Master database schema and data migrations across ORMs (Sequelize, TypeORM, Prisma), including rollback strategies and zero-downtime deployments.
When to Use This Skill
- Migrating between different ORMs
- Performing schema transformations
- Moving data between databases
- Implementing rollback procedures
- Zero-downtime deployments
- Database version upgrades
- Data model refactoring
ORM Migrations
Sequelize Migrations
javascript
// migrations/20231201-create-users.jsmodule.exports = {up: async (queryInterface, Sequelize) => {await queryInterface.createTable("users", {id: {type: Sequelize.INTEGER,primaryKey: true,autoIncrement: true,},email: {type: Sequelize.STRING,unique: true,allowNull: false,},createdAt: Sequelize.DATE,updatedAt: Sequelize.DATE,});},down: async (queryInterface, Sequelize) => {await queryInterface.dropTable("users");},};// Run: npx sequelize-cli db:migrate// Rollback: npx sequelize-cli db:migrate:undo
TypeORM Migrations
typescript
// migrations/1701234567-CreateUsers.tsimport { MigrationInterface, QueryRunner, Table } from "typeorm";export class CreateUsers1701234567 implements MigrationInterface {public async up(queryRunner: QueryRunner): Promise<void> {await queryRunner.createTable(new Table({name: "users",columns: [{name: "id",type: "int",isPrimary: true,isGenerated: true,generationStrategy: "increment",},{name: "email",type: "varchar",isUnique: true,},{name: "created_at",type: "timestamp",default: "CURRENT_TIMESTAMP",},],}),);}public async down(queryRunner: QueryRunner): Promise<void> {await queryRunner.dropTable("users");}}// Run: npm run typeorm migration:run// Rollback: npm run typeorm migration:revert
Prisma Migrations
prisma
// schema.prismamodel User {id Int @id @default(autoincrement())email String @uniquecreatedAt DateTime @default(now())}// Generate migration: npx prisma migrate dev --name create_users// Apply: npx prisma migrate deploy
Schema Transformations
Adding Columns with Defaults
javascript
// Safe migration: add column with defaultmodule.exports = {up: async (queryInterface, Sequelize) => {await queryInterface.addColumn("users", "status", {type: Sequelize.STRING,defaultValue: "active",allowNull: false,});},down: async (queryInterface) => {await queryInterface.removeColumn("users", "status");},};
Renaming Columns (Zero Downtime)
javascript
// Step 1: Add new columnmodule.exports = {up: async (queryInterface, Sequelize) => {await queryInterface.addColumn("users", "full_name", {type: Sequelize.STRING,});// Copy data from old columnawait queryInterface.sequelize.query("UPDATE users SET full_name = name");},down: async (queryInterface) => {await queryInterface.removeColumn("users", "full_name");},};// Step 2: Update application to use new column// Step 3: Remove old columnmodule.exports = {up: async (queryInterface) => {await queryInterface.removeColumn("users", "name");},down: async (queryInterface, Sequelize) => {await queryInterface.addColumn("users", "name", {type: Sequelize.STRING,});},};
Changing Column Types
javascript
module.exports = {up: async (queryInterface, Sequelize) => {// For large tables, use multi-step approach// 1. Add new columnawait queryInterface.addColumn("users", "age_new", {type: Sequelize.INTEGER,});// 2. Copy and transform dataawait queryInterface.sequelize.query(`UPDATE usersSET age_new = CAST(age AS INTEGER)WHERE age IS NOT NULL`);// 3. Drop old columnawait queryInterface.removeColumn("users", "age");// 4. Rename new columnawait queryInterface.renameColumn("users", "age_new", "age");},down: async (queryInterface, Sequelize) => {await queryInterface.changeColumn("users", "age", {type: Sequelize.STRING,});},};
Data Transformations
Complex Data Migration
javascript
module.exports = {up: async (queryInterface, Sequelize) => {// Get all recordsconst [users] = await queryInterface.sequelize.query("SELECT id, address_string FROM users",);// Transform each recordfor (const user of users) {const addressParts = user.address_string.split(",");await queryInterface.sequelize.query(`UPDATE usersSET street = :street,city = :city,state = :stateWHERE id = :id`,{replacements: {id: user.id,street: addressParts[0]?.trim(),city: addressParts[1]?.trim(),state: addressParts[2]?.trim(),},},);}// Drop old columnawait queryInterface.removeColumn("users", "address_string");},down: async (queryInterface, Sequelize) => {// Reconstruct original columnawait queryInterface.addColumn("users", "address_string", {type: Sequelize.STRING,});await queryInterface.sequelize.query(`UPDATE usersSET address_string = CONCAT(street, ', ', city, ', ', state)`);await queryInterface.removeColumn("users", "street");await queryInterface.removeColumn("users", "city");await queryInterface.removeColumn("users", "state");},};
Rollback Strategies
Transaction-Based Migrations
javascript
module.exports = {up: async (queryInterface, Sequelize) => {const transaction = await queryInterface.sequelize.transaction();try {await queryInterface.addColumn("users","verified",{ type: Sequelize.BOOLEAN, defaultValue: false },{ transaction },);await queryInterface.sequelize.query("UPDATE users SET verified = true WHERE email_verified_at IS NOT NULL",{ transaction },);await transaction.commit();} catch (error) {await transaction.rollback();throw error;}},down: async (queryInterface) => {await queryInterface.removeColumn("users", "verified");},};
Checkpoint-Based Rollback
javascript
module.exports = {up: async (queryInterface, Sequelize) => {// Create backup tableawait queryInterface.sequelize.query("CREATE TABLE users_backup AS SELECT * FROM users",);try {// Perform migrationawait queryInterface.addColumn("users", "new_field", {type: Sequelize.STRING,});// Verify migrationconst [result] = await queryInterface.sequelize.query("SELECT COUNT(*) as count FROM users WHERE new_field IS NULL",);if (result[0].count > 0) {throw new Error("Migration verification failed");}// Drop backupawait queryInterface.dropTable("users_backup");} catch (error) {// Restore from backupawait queryInterface.sequelize.query("DROP TABLE users");await queryInterface.sequelize.query("CREATE TABLE users AS SELECT * FROM users_backup",);await queryInterface.dropTable("users_backup");throw error;}},};
Zero-Downtime Migrations
Blue-Green Deployment Strategy
javascript
// Phase 1: Make changes backward compatiblemodule.exports = {up: async (queryInterface, Sequelize) => {// Add new column (both old and new code can work)await queryInterface.addColumn("users", "email_new", {type: Sequelize.STRING,});},};// Phase 2: Deploy code that writes to both columns// Phase 3: Backfill datamodule.exports = {up: async (queryInterface) => {await queryInterface.sequelize.query(`UPDATE usersSET email_new = emailWHERE email_new IS NULL`);},};// Phase 4: Deploy code that reads from new column// Phase 5: Remove old columnmodule.exports = {up: async (queryInterface) => {await queryInterface.removeColumn("users", "email");},};
Cross-Database Migrations
PostgreSQL to MySQL
javascript
// Handle differencesmodule.exports = {up: async (queryInterface, Sequelize) => {const dialectName = queryInterface.sequelize.getDialect();if (dialectName === "mysql") {await queryInterface.createTable("users", {id: {type: Sequelize.INTEGER,primaryKey: true,autoIncrement: true,},data: {type: Sequelize.JSON, // MySQL JSON type},});} else if (dialectName === "postgres") {await queryInterface.createTable("users", {id: {type: Sequelize.INTEGER,primaryKey: true,autoIncrement: true,},data: {type: Sequelize.JSONB, // PostgreSQL JSONB type},});}},};
Resources
- references/orm-switching.md: ORM migration guides
- references/schema-migration.md: Schema transformation patterns
- references/data-transformation.md: Data migration scripts
- references/rollback-strategies.md: Rollback procedures
- assets/schema-migration-template.sql: SQL migration templates
- assets/data-migration-script.py: Data migration utilities
- scripts/test-migration.sh: Migration testing script
Best Practices
- Always Provide Rollback: Every up() needs a down()
- Test Migrations: Test on staging first
- Use Transactions: Atomic migrations when possible
- Backup First: Always backup before migration
- Small Changes: Break into small, incremental steps
- Monitor: Watch for errors during deployment
- Document: Explain why and how
- Idempotent: Migrations should be rerunnable
Common Pitfalls
- Not testing rollback procedures
- Making breaking changes without downtime strategy
- Forgetting to handle NULL values
- Not considering index performance
- Ignoring foreign key constraints
- Migrating too much data at once