{"id":"c44db3a7-db80-49a5-8ad9-c06b45df38db","shortId":"MvYxxq","kind":"skill","title":"database-migration","tagline":"Master database schema and data migrations across ORMs (Sequelize, TypeORM, Prisma), including rollback strategies and zero-downtime deployments.","description":"# Database Migration\n\nMaster database schema and data migrations across ORMs (Sequelize, TypeORM, Prisma), including rollback strategies and zero-downtime deployments.\n\n## Do not use this skill when\n\n- The task is unrelated to database migration\n- You need a different domain or tool outside this scope\n\n## Instructions\n\n- Clarify goals, constraints, and required inputs.\n- Apply relevant best practices and validate outcomes.\n- Provide actionable steps and verification.\n- If detailed examples are required, open `resources/implementation-playbook.md`.\n\n## Use this skill when\n\n- Migrating between different ORMs\n- Performing schema transformations\n- Moving data between databases\n- Implementing rollback procedures\n- Zero-downtime deployments\n- Database version upgrades\n- Data model refactoring\n\n## ORM Migrations\n\n### Sequelize Migrations\n```javascript\n// migrations/20231201-create-users.js\nmodule.exports = {\n  up: async (queryInterface, Sequelize) => {\n    await queryInterface.createTable('users', {\n      id: {\n        type: Sequelize.INTEGER,\n        primaryKey: true,\n        autoIncrement: true\n      },\n      email: {\n        type: Sequelize.STRING,\n        unique: true,\n        allowNull: false\n      },\n      createdAt: Sequelize.DATE,\n      updatedAt: Sequelize.DATE\n    });\n  },\n\n  down: async (queryInterface, Sequelize) => {\n    await queryInterface.dropTable('users');\n  }\n};\n\n// Run: npx sequelize-cli db:migrate\n// Rollback: npx sequelize-cli db:migrate:undo\n```\n\n### TypeORM Migrations\n```typescript\n// migrations/1701234567-CreateUsers.ts\nimport { MigrationInterface, QueryRunner, Table } from 'typeorm';\n\nexport class CreateUsers1701234567 implements MigrationInterface {\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.createTable(\n      new Table({\n        name: 'users',\n        columns: [\n          {\n            name: 'id',\n            type: 'int',\n            isPrimary: true,\n            isGenerated: true,\n            generationStrategy: 'increment'\n          },\n          {\n            name: 'email',\n            type: 'varchar',\n            isUnique: true\n          },\n          {\n            name: 'created_at',\n            type: 'timestamp',\n            default: 'CURRENT_TIMESTAMP'\n          }\n        ]\n      })\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.dropTable('users');\n  }\n}\n\n// Run: npm run typeorm migration:run\n// Rollback: npm run typeorm migration:revert\n```\n\n### Prisma Migrations\n```prisma\n// schema.prisma\nmodel User {\n  id        Int      @id @default(autoincrement())\n  email     String   @unique\n  createdAt DateTime @default(now())\n}\n\n// Generate migration: npx prisma migrate dev --name create_users\n// Apply: npx prisma migrate deploy\n```\n\n## Schema Transformations\n\n### Adding Columns with Defaults\n```javascript\n// Safe migration: add column with default\nmodule.exports = {\n  up: async (queryInterface, Sequelize) => {\n    await queryInterface.addColumn('users', 'status', {\n      type: Sequelize.STRING,\n      defaultValue: 'active',\n      allowNull: false\n    });\n  },\n\n  down: async (queryInterface) => {\n    await queryInterface.removeColumn('users', 'status');\n  }\n};\n```\n\n### Renaming Columns (Zero Downtime)\n```javascript\n// Step 1: Add new column\nmodule.exports = {\n  up: async (queryInterface, Sequelize) => {\n    await queryInterface.addColumn('users', 'full_name', {\n      type: Sequelize.STRING\n    });\n\n    // Copy data from old column\n    await queryInterface.sequelize.query(\n      'UPDATE users SET full_name = name'\n    );\n  },\n\n  down: async (queryInterface) => {\n    await queryInterface.removeColumn('users', 'full_name');\n  }\n};\n\n// Step 2: Update application to use new column\n\n// Step 3: Remove old column\nmodule.exports = {\n  up: async (queryInterface) => {\n    await queryInterface.removeColumn('users', 'name');\n  },\n\n  down: async (queryInterface, Sequelize) => {\n    await queryInterface.addColumn('users', 'name', {\n      type: Sequelize.STRING\n    });\n  }\n};\n```\n\n### Changing Column Types\n```javascript\nmodule.exports = {\n  up: async (queryInterface, Sequelize) => {\n    // For large tables, use multi-step approach\n\n    // 1. Add new column\n    await queryInterface.addColumn('users', 'age_new', {\n      type: Sequelize.INTEGER\n    });\n\n    // 2. Copy and transform data\n    await queryInterface.sequelize.query(`\n      UPDATE users\n      SET age_new = CAST(age AS INTEGER)\n      WHERE age IS NOT NULL\n    `);\n\n    // 3. Drop old column\n    await queryInterface.removeColumn('users', 'age');\n\n    // 4. Rename new column\n    await queryInterface.renameColumn('users', 'age_new', 'age');\n  },\n\n  down: async (queryInterface, Sequelize) => {\n    await queryInterface.changeColumn('users', 'age', {\n      type: Sequelize.STRING\n    });\n  }\n};\n```\n\n## Data Transformations\n\n### Complex Data Migration\n```javascript\nmodule.exports = {\n  up: async (queryInterface, Sequelize) => {\n    // Get all records\n    const [users] = await queryInterface.sequelize.query(\n      'SELECT id, address_string FROM users'\n    );\n\n    // Transform each record\n    for (const user of users) {\n      const addressParts = user.address_string.split(',');\n\n      await queryInterface.sequelize.query(\n        `UPDATE users\n         SET street = :street,\n             city = :city,\n             state = :state\n         WHERE id = :id`,\n        {\n          replacements: {\n            id: user.id,\n            street: addressParts[0]?.trim(),\n            city: addressParts[1]?.trim(),\n            state: addressParts[2]?.trim()\n          }\n        }\n      );\n    }\n\n    // Drop old column\n    await queryInterface.removeColumn('users', 'address_string');\n  },\n\n  down: async (queryInterface, Sequelize) => {\n    // Reconstruct original column\n    await queryInterface.addColumn('users', 'address_string', {\n      type: Sequelize.STRING\n    });\n\n    await queryInterface.sequelize.query(`\n      UPDATE users\n      SET address_string = CONCAT(street, ', ', city, ', ', state)\n    `);\n\n    await queryInterface.removeColumn('users', 'street');\n    await queryInterface.removeColumn('users', 'city');\n    await queryInterface.removeColumn('users', 'state');\n  }\n};\n```\n\n## Rollback Strategies\n\n### Transaction-Based Migrations\n```javascript\nmodule.exports = {\n  up: async (queryInterface, Sequelize) => {\n    const transaction = await queryInterface.sequelize.transaction();\n\n    try {\n      await queryInterface.addColumn(\n        'users',\n        'verified',\n        { type: Sequelize.BOOLEAN, defaultValue: false },\n        { transaction }\n      );\n\n      await queryInterface.sequelize.query(\n        'UPDATE users SET verified = true WHERE email_verified_at IS NOT NULL',\n        { transaction }\n      );\n\n      await transaction.commit();\n    } catch (error) {\n      await transaction.rollback();\n      throw error;\n    }\n  },\n\n  down: async (queryInterface) => {\n    await queryInterface.removeColumn('users', 'verified');\n  }\n};\n```\n\n### Checkpoint-Based Rollback\n```javascript\nmodule.exports = {\n  up: async (queryInterface, Sequelize) => {\n    // Create backup table\n    await queryInterface.sequelize.query(\n      'CREATE TABLE users_backup AS SELECT * FROM users'\n    );\n\n    try {\n      // Perform migration\n      await queryInterface.addColumn('users', 'new_field', {\n        type: Sequelize.STRING\n      });\n\n      // Verify migration\n      const [result] = await queryInterface.sequelize.query(\n        \"SELECT COUNT(*) as count FROM users WHERE new_field IS NULL\"\n      );\n\n      if (result[0].count > 0) {\n        throw new Error('Migration verification failed');\n      }\n\n      // Drop backup\n      await queryInterface.dropTable('users_backup');\n    } catch (error) {\n      // Restore from backup\n      await queryInterface.sequelize.query('DROP TABLE users');\n      await queryInterface.sequelize.query(\n        'CREATE TABLE users AS SELECT * FROM users_backup'\n      );\n      await queryInterface.dropTable('users_backup');\n      throw error;\n    }\n  }\n};\n```\n\n## Zero-Downtime Migrations\n\n### Blue-Green Deployment Strategy\n```javascript\n// Phase 1: Make changes backward compatible\nmodule.exports = {\n  up: async (queryInterface, Sequelize) => {\n    // Add new column (both old and new code can work)\n    await queryInterface.addColumn('users', 'email_new', {\n      type: Sequelize.STRING\n    });\n  }\n};\n\n// Phase 2: Deploy code that writes to both columns\n\n// Phase 3: Backfill data\nmodule.exports = {\n  up: async (queryInterface) => {\n    await queryInterface.sequelize.query(`\n      UPDATE users\n      SET email_new = email\n      WHERE email_new IS NULL\n    `);\n  }\n};\n\n// Phase 4: Deploy code that reads from new column\n\n// Phase 5: Remove old column\nmodule.exports = {\n  up: async (queryInterface) => {\n    await queryInterface.removeColumn('users', 'email');\n  }\n};\n```\n\n## Cross-Database Migrations\n\n### PostgreSQL to MySQL\n```javascript\n// Handle differences\nmodule.exports = {\n  up: async (queryInterface, Sequelize) => {\n    const dialectName = queryInterface.sequelize.getDialect();\n\n    if (dialectName === 'mysql') {\n      await queryInterface.createTable('users', {\n        id: {\n          type: Sequelize.INTEGER,\n          primaryKey: true,\n          autoIncrement: true\n        },\n        data: {\n          type: Sequelize.JSON  // MySQL JSON type\n        }\n      });\n    } else if (dialectName === 'postgres') {\n      await queryInterface.createTable('users', {\n        id: {\n          type: Sequelize.INTEGER,\n          primaryKey: true,\n          autoIncrement: true\n        },\n        data: {\n          type: Sequelize.JSONB  // PostgreSQL JSONB type\n        }\n      });\n    }\n  }\n};\n```\n\n## Resources\n\n- **references/orm-switching.md**: ORM migration guides\n- **references/schema-migration.md**: Schema transformation patterns\n- **references/data-transformation.md**: Data migration scripts\n- **references/rollback-strategies.md**: Rollback procedures\n- **assets/schema-migration-template.sql**: SQL migration templates\n- **assets/data-migration-script.py**: Data migration utilities\n- **scripts/test-migration.sh**: Migration testing script\n\n## Best Practices\n\n1. **Always Provide Rollback**: Every up() needs a down()\n2. **Test Migrations**: Test on staging first\n3. **Use Transactions**: Atomic migrations when possible\n4. **Backup First**: Always backup before migration\n5. **Small Changes**: Break into small, incremental steps\n6. **Monitor**: Watch for errors during deployment\n7. **Document**: Explain why and how\n8. **Idempotent**: Migrations should be rerunnable\n\n## Common Pitfalls\n\n- Not testing rollback procedures\n- Making breaking changes without downtime strategy\n- Forgetting to handle NULL values\n- Not considering index performance\n- Ignoring foreign key constraints\n- Migrating too much data at once\n\n## Limitations\n- Use this skill only when the task clearly matches the scope described above.\n- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.\n- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.","tags":["database","migration","antigravity","awesome","skills","sickn33","agent-skills","agentic-skills","ai-agent-skills","ai-agents","ai-coding","ai-workflows"],"capabilities":["skill","source-sickn33","skill-database-migration","topic-agent-skills","topic-agentic-skills","topic-ai-agent-skills","topic-ai-agents","topic-ai-coding","topic-ai-workflows","topic-antigravity","topic-antigravity-skills","topic-claude-code","topic-claude-code-skills","topic-codex-cli","topic-codex-skills"],"categories":["antigravity-awesome-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/sickn33/antigravity-awesome-skills/database-migration","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add sickn33/antigravity-awesome-skills","source_repo":"https://github.com/sickn33/antigravity-awesome-skills","install_from":"skills.sh"}},"qualityScore":"0.700","qualityRationale":"deterministic score 0.70 from registry signals: · indexed on github topic:agent-skills · 34831 github stars · SKILL.md body (11,135 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-04-24T06:51:01.139Z","embedding":null,"createdAt":"2026-04-18T21:35:39.958Z","updatedAt":"2026-04-24T06:51:01.139Z","lastSeenAt":"2026-04-24T06:51:01.139Z","tsv":"'0':520,683,685 '1':321,406,524,735,901 '2':359,417,528,763,910 '3':367,438,772,917 '4':446,793,924 '5':802,931 '6':939 '7':946 '8':952 'across':10,31 'action':82 'activ':305 'ad':282 'add':289,322,407,745 'address':486,536,548,557 'addresspart':499,519,523,527 'age':413,427,430,434,445,453,455,463 'allownul':147,306 'alway':902,927 'appli':74,275 'applic':361 'approach':405 'ask':1022 'assets/data-migration-script.py':891 'assets/schema-migration-template.sql':887 'async':129,154,191,228,295,309,327,351,373,380,395,457,474,539,584,625,638,742,777,808,826 'atom':920 'autoincr':140,258,843,863 'await':132,157,196,233,298,311,330,342,353,375,383,410,422,442,450,460,482,501,533,545,552,563,567,571,589,592,601,616,620,627,644,657,668,694,703,708,718,755,779,810,835,855 'backfil':773 'backup':642,649,693,697,702,717,721,925,928 'backward':738 'base':579,633 'best':76,899 'blue':729 'blue-green':728 'boundari':1030 'break':934,965 'cast':429 'catch':618,698 'chang':389,737,933,966 'checkpoint':632 'checkpoint-bas':631 'citi':508,509,522,561,570 'clarif':1024 'clarifi':68 'class':186 'clear':997 'cli':164,171 'code':752,765,795 'column':202,283,290,316,324,341,365,370,390,409,441,449,532,544,747,770,800,805 'common':958 'compat':739 'complex':468 'concat':559 'consid':976 'const':480,494,498,587,666,829 'constraint':70,982 'copi':337,418 'count':671,673,684 'creat':220,273,641,646,710 'createdat':149,262 'createusers1701234567':187 'criteria':1033 'cross':815 'cross-databas':814 'current':225 'data':8,29,105,118,338,421,466,469,774,845,865,881,892,986 'databas':2,5,23,26,55,107,115,816 'database-migr':1 'datetim':263 'db':165,172 'default':224,257,264,285,292 'defaultvalu':304,598 'deploy':22,43,114,279,731,764,794,945 'describ':1001 'detail':87 'dev':271 'dialectnam':830,833,853 'differ':60,99,823 'document':947 'domain':61 'downtim':21,42,113,318,726,968 'drop':439,530,692,705 'els':851 'email':142,214,259,609,758,784,786,788,813 'environ':1013 'environment-specif':1012 'error':619,623,688,699,723,943 'everi':905 'exampl':88 'expert':1018 'explain':948 'export':185 'fail':691 'fals':148,307,599 'field':661,678 'first':916,926 'foreign':980 'forget':970 'full':333,347,356 'generat':266 'generationstrategi':211 'get':477 'goal':69 'green':730 'guid':875 'handl':822,972 'id':135,204,254,256,485,513,514,516,838,858 'idempot':953 'ignor':979 'implement':108,188 'import':179 'includ':15,36 'increment':212,937 'index':977 'input':73,1027 'instruct':67 'int':206,255 'integ':432 'isgener':209 'isprimari':207 'isuniqu':217 'javascript':125,286,319,392,471,581,635,733,821 'json':849 'jsonb':869 'key':981 'larg':399 'limit':989 'make':736,964 'master':4,25 'match':998 'migrat':3,9,24,30,56,97,122,124,166,173,176,240,246,249,267,270,278,288,470,580,656,665,689,727,817,874,882,889,893,896,912,921,930,954,983 'migrationinterfac':180,189 'migrations/1701234567-createusers.ts':178 'migrations/20231201-create-users.js':126 'miss':1035 'model':119,252 'module.exports':127,293,325,371,393,472,582,636,740,775,806,824 'monitor':940 'move':104 'much':985 'multi':403 'multi-step':402 'mysql':820,834,848 'name':200,203,213,219,272,334,348,349,357,378,386 'need':58,907 'new':198,323,364,408,414,428,448,454,660,677,687,746,751,759,785,789,799 'npm':237,243 'npx':161,168,268,276 'null':437,614,680,791,973 'old':340,369,440,531,749,804 'open':91 'origin':543 'orm':11,32,100,121,873 'outcom':80 'output':1007 'outsid':64 'pattern':879 'perform':101,655,978 'permiss':1028 'phase':734,762,771,792,801 'pitfal':959 'possibl':923 'postgr':854 'postgresql':818,868 'practic':77,900 'primarykey':138,841,861 'prisma':14,35,248,250,269,277 'procedur':110,886,963 'promis':195,232 'provid':81,903 'public':190,227 'queryinterfac':130,155,296,310,328,352,374,381,396,458,475,540,585,626,639,743,778,809,827 'queryinterface.addcolumn':299,331,384,411,546,593,658,756 'queryinterface.changecolumn':461 'queryinterface.createtable':133,836,856 'queryinterface.droptable':158,695,719 'queryinterface.removecolumn':312,354,376,443,534,564,568,572,628,811 'queryinterface.renamecolumn':451 'queryinterface.sequelize.getdialect':831 'queryinterface.sequelize.query':343,423,483,502,553,602,645,669,704,709,780 'queryinterface.sequelize.transaction':590 'queryrunn':181,193,194,230,231 'queryrunner.createtable':197 'queryrunner.droptable':234 'read':797 'reconstruct':542 'record':479,492 'refactor':120 'references/data-transformation.md':880 'references/orm-switching.md':872 'references/rollback-strategies.md':884 'references/schema-migration.md':876 'relev':75 'remov':368,803 'renam':315,447 'replac':515 'requir':72,90,1026 'rerunn':957 'resourc':871 'resources/implementation-playbook.md':92 'restor':700 'result':667,682 'revert':247 'review':1019 'rollback':16,37,109,167,242,575,634,885,904,962 'run':160,236,238,241,244 'safe':287 'safeti':1029 'schema':6,27,102,280,877 'schema.prisma':251 'scope':66,1000 'script':883,898 'scripts/test-migration.sh':895 'select':484,651,670,714 'sequel':12,33,123,131,156,163,170,297,329,382,397,459,476,541,586,640,744,828 'sequelize-c':162,169 'sequelize.boolean':597 'sequelize.date':150,152 'sequelize.integer':137,416,840,860 'sequelize.json':847 'sequelize.jsonb':867 'sequelize.string':144,303,336,388,465,551,663,761 'set':346,426,505,556,605,783 'skill':48,95,992 'skill-database-migration' 'small':932,936 'source-sickn33' 'specif':1014 'sql':888 'stage':915 'state':510,511,526,562,574 'status':301,314 'step':83,320,358,366,404,938 'stop':1020 'strategi':17,38,576,732,969 'street':506,507,518,560,566 'string':260,487,537,549,558 'substitut':1010 'success':1032 'tabl':182,199,400,643,647,706,711 'task':51,996 'templat':890 'test':897,911,913,961,1016 'throw':622,686,722 'timestamp':223,226 'tool':63 'topic-agent-skills' 'topic-agentic-skills' 'topic-ai-agent-skills' 'topic-ai-agents' 'topic-ai-coding' 'topic-ai-workflows' 'topic-antigravity' 'topic-antigravity-skills' 'topic-claude-code' 'topic-claude-code-skills' 'topic-codex-cli' 'topic-codex-skills' 'transact':578,588,600,615,919 'transaction-bas':577 'transaction.commit':617 'transaction.rollback':621 'transform':103,281,420,467,490,878 'treat':1005 'tri':591,654 'trim':521,525,529 'true':139,141,146,208,210,218,607,842,844,862,864 'type':136,143,205,215,222,302,335,387,391,415,464,550,596,662,760,839,846,850,859,866,870 'typeorm':13,34,175,184,239,245 'typescript':177 'undo':174 'uniqu':145,261 'unrel':53 'updat':344,360,424,503,554,603,781 'updatedat':151 'upgrad':117 'use':46,93,363,401,918,990 'user':134,159,201,235,253,274,300,313,332,345,355,377,385,412,425,444,452,462,481,489,495,497,504,535,547,555,565,569,573,594,604,629,648,653,659,675,696,707,712,716,720,757,782,812,837,857 'user.address_string.split':500 'user.id':517 'util':894 'valid':79,1015 'valu':974 'varchar':216 'verif':85,690 'verifi':595,606,610,630,664 'version':116 'watch':941 'without':967 'work':754 'write':767 'zero':20,41,112,317,725 'zero-downtim':19,40,111,724","prices":[{"id":"b370e94f-e770-43ca-84b8-9f853cf98e18","listingId":"c44db3a7-db80-49a5-8ad9-c06b45df38db","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"sickn33","category":"antigravity-awesome-skills","install_from":"skills.sh"},"createdAt":"2026-04-18T21:35:39.958Z"}],"sources":[{"listingId":"c44db3a7-db80-49a5-8ad9-c06b45df38db","source":"github","sourceId":"sickn33/antigravity-awesome-skills/database-migration","sourceUrl":"https://github.com/sickn33/antigravity-awesome-skills/tree/main/skills/database-migration","isPrimary":false,"firstSeenAt":"2026-04-18T21:35:39.958Z","lastSeenAt":"2026-04-24T06:51:01.139Z"}],"details":{"listingId":"c44db3a7-db80-49a5-8ad9-c06b45df38db","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"sickn33","slug":"database-migration","github":{"repo":"sickn33/antigravity-awesome-skills","stars":34831,"topics":["agent-skills","agentic-skills","ai-agent-skills","ai-agents","ai-coding","ai-workflows","antigravity","antigravity-skills","claude-code","claude-code-skills","codex-cli","codex-skills","cursor","cursor-skills","developer-tools","gemini-cli","gemini-skills","kiro","mcp","skill-library"],"license":"mit","html_url":"https://github.com/sickn33/antigravity-awesome-skills","pushed_at":"2026-04-24T06:41:17Z","description":"Installable GitHub library of 1,400+ agentic skills for Claude Code, Cursor, Codex CLI, Gemini CLI, Antigravity, and more. Includes installer CLI, bundles, workflows, and official/community skill collections.","skill_md_sha":"1b1e19acb254079446a937ade28a760f70b4d61f","skill_md_path":"skills/database-migration/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/sickn33/antigravity-awesome-skills/tree/main/skills/database-migration"},"layout":"multi","source":"github","category":"antigravity-awesome-skills","frontmatter":{"name":"database-migration","description":"Master database schema and data migrations across ORMs (Sequelize, TypeORM, Prisma), including rollback strategies and zero-downtime deployments."},"skills_sh_url":"https://skills.sh/sickn33/antigravity-awesome-skills/database-migration"},"updatedAt":"2026-04-24T06:51:01.139Z"}}