← Back to Skills Marketplace
emiltsoi

Database Migration

by emiltsoi · GitHub ↗ · v1.0.0 · MIT-0
cross-platform ✓ Security Clean
144
Downloads
0
Stars
1
Active Installs
1
Versions
Install in OpenClaw
/install database-migration
Description
Execute database migrations across ORMs and platforms with zero-downtime strategies, data transformation, and rollback procedures. Use when migrating databas...
README (SKILL.md)

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

// migrations/20231201-create-users.js
module.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

// migrations/1701234567-CreateUsers.ts
import { MigrationInterface, QueryRunner, Table } from "typeorm";

export class CreateUsers1701234567 implements MigrationInterface {
  public async up(queryRunner: QueryRunner): Promise\x3Cvoid> {
    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\x3Cvoid> {
    await queryRunner.dropTable("users");
  }
}

// Run: npm run typeorm migration:run
// Rollback: npm run typeorm migration:revert

Prisma Migrations

// schema.prisma
model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  createdAt DateTime @default(now())
}

// Generate migration: npx prisma migrate dev --name create_users
// Apply: npx prisma migrate deploy

Schema Transformations

Adding Columns with Defaults

// Safe migration: add column with default
module.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)

// Step 1: Add new column
module.exports = {
  up: async (queryInterface, Sequelize) => {
    await queryInterface.addColumn("users", "full_name", {
      type: Sequelize.STRING,
    });

    // Copy data from old column
    await 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 column
module.exports = {
  up: async (queryInterface) => {
    await queryInterface.removeColumn("users", "name");
  },

  down: async (queryInterface, Sequelize) => {
    await queryInterface.addColumn("users", "name", {
      type: Sequelize.STRING,
    });
  },
};

Changing Column Types

module.exports = {
  up: async (queryInterface, Sequelize) => {
    // For large tables, use multi-step approach

    // 1. Add new column
    await queryInterface.addColumn("users", "age_new", {
      type: Sequelize.INTEGER,
    });

    // 2. Copy and transform data
    await queryInterface.sequelize.query(`
      UPDATE users
      SET age_new = CAST(age AS INTEGER)
      WHERE age IS NOT NULL
    `);

    // 3. Drop old column
    await queryInterface.removeColumn("users", "age");

    // 4. Rename new column
    await queryInterface.renameColumn("users", "age_new", "age");
  },

  down: async (queryInterface, Sequelize) => {
    await queryInterface.changeColumn("users", "age", {
      type: Sequelize.STRING,
    });
  },
};

Data Transformations

Complex Data Migration

module.exports = {
  up: async (queryInterface, Sequelize) => {
    // Get all records
    const [users] = await queryInterface.sequelize.query(
      "SELECT id, address_string FROM users",
    );

    // Transform each record
    for (const user of users) {
      const addressParts = user.address_string.split(",");

      await queryInterface.sequelize.query(
        `UPDATE users
         SET street = :street,
             city = :city,
             state = :state
         WHERE id = :id`,
        {
          replacements: {
            id: user.id,
            street: addressParts[0]?.trim(),
            city: addressParts[1]?.trim(),
            state: addressParts[2]?.trim(),
          },
        },
      );
    }

    // Drop old column
    await queryInterface.removeColumn("users", "address_string");
  },

  down: async (queryInterface, Sequelize) => {
    // Reconstruct original column
    await queryInterface.addColumn("users", "address_string", {
      type: Sequelize.STRING,
    });

    await queryInterface.sequelize.query(`
      UPDATE users
      SET 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

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

module.exports = {
  up: async (queryInterface, Sequelize) => {
    // Create backup table
    await queryInterface.sequelize.query(
      "CREATE TABLE users_backup AS SELECT * FROM users",
    );

    try {
      // Perform migration
      await queryInterface.addColumn("users", "new_field", {
        type: Sequelize.STRING,
      });

      // Verify migration
      const [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 backup
      await queryInterface.dropTable("users_backup");
    } catch (error) {
      // Restore from backup
      await 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

// Phase 1: Make changes backward compatible
module.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 data
module.exports = {
  up: async (queryInterface) => {
    await queryInterface.sequelize.query(`
      UPDATE users
      SET email_new = email
      WHERE email_new IS NULL
    `);
  },
};

// Phase 4: Deploy code that reads from new column

// Phase 5: Remove old column
module.exports = {
  up: async (queryInterface) => {
    await queryInterface.removeColumn("users", "email");
  },
};

Cross-Database Migrations

PostgreSQL to MySQL

// Handle differences
module.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
        },
      });
    }
  },
};
Usage Guidance
This skill is a collection of migration recipes, not an agent that will fetch secrets or install itself. Before using: (1) ensure the Node/ORM CLIs referenced (npx, npm, prisma, sequelize-cli, typeorm) are available on the system; (2) run all changes first in a staging environment and take full backups/snapshots; (3) review every SQL UPDATE/DROP in the snippets to confirm they match your schema and constraints; (4) never paste production DB credentials into untrusted prompts — supply connection strings only to the migration runtime you control; (5) if you need automated execution, prefer running these scripts from a CI pipeline or a controlled maintenance window rather than letting an agent run them autonomously.
Capability Analysis
Type: OpenClaw Skill Name: database-migration Version: 1.0.0 The skill bundle provides standard educational content and code examples for database migrations using Sequelize, TypeORM, and Prisma. It covers common tasks such as schema transformations, data migrations, and rollback strategies without any evidence of malicious intent, data exfiltration, or prompt injection. All code snippets in SKILL.md follow standard ORM patterns.
Capability Assessment
Purpose & Capability
The skill's name, description, and SKILL.md content align: it provides migration patterns for Sequelize, TypeORM, Prisma and describes zero-downtime and rollback strategies. One mismatch: the metadata declares no required binaries, but the instructions reference npx, npm scripts, prisma and sequelize-cli commands — so the skill omits declaring the real-world tooling it expects.
Instruction Scope
All instructions and code snippets stay within the domain of database migrations: creating/dropping tables, adding/renaming columns, copying/transformation queries, and CLI migration commands. The guidance includes SQL UPDATEs and potentially destructive operations (DROP, REMOVE COLUMN) which are appropriate for a migration skill but inherently risky if run without backups or staging.
Install Mechanism
This is an instruction-only skill with no install spec or code files, so nothing will be written to disk by the skill package itself. That is low-risk from an install perspective. However, the runtime instructions assume use of external CLIs (npm/npx/prisma/cli) which the skill does not install.
Credentials
The skill declares no required environment variables or primary credential, yet in practice migrations require database connection strings/credentials (e.g., DATABASE_URL) to be present in the environment or config. The SKILL.md does not ask the agent to read system or unrelated credentials, but it assumes DB access will be provided externally — the absence of declared required env vars is a transparency gap.
Persistence & Privilege
The skill is not always-enabled and is user-invocable. It does not request to modify other skills or system-wide agent settings. There is no evidence the skill persistently stores or escalates privileges on the agent platform.
How to Use
  1. Make sure OpenClaw is installed (local or Docker)
  2. Run the install command in chat: /install database-migration
  3. After installation, invoke the skill by name or use /database-migration
  4. Provide required inputs per the skill's parameter spec and get structured output
Version History
v1.0.0
- Initial release of the database-migration skill. - Provides step-by-step guides for schema and data migrations using Sequelize, TypeORM, and Prisma. - Includes best practices for zero-downtime deployment, rollback procedures, and complex data transformations. - Covers migration patterns such as adding/removing/renaming columns, changing data types, and transactional migrations. - Offers examples for safe schema evolution and data model refactoring across multiple ORMs.
Metadata
Slug database-migration
Version 1.0.0
License MIT-0
All-time Installs 1
Active Installs 1
Total Versions 1
Frequently Asked Questions

What is Database Migration?

Execute database migrations across ORMs and platforms with zero-downtime strategies, data transformation, and rollback procedures. Use when migrating databas... It is an AI Agent Skill for Claude Code / OpenClaw, with 144 downloads so far.

How do I install Database Migration?

Run "/install database-migration" in the OpenClaw or Claude Code chat to install it in one step — no extra setup required.

Is Database Migration free?

Yes, Database Migration is completely free, licensed under MIT-0. You can download, install and use it at no cost.

Which platforms does Database Migration support?

Database Migration is cross-platform and runs anywhere OpenClaw / Claude Code is available (cross-platform).

Who created Database Migration?

It is built and maintained by emiltsoi (@emiltsoi); the current version is v1.0.0.

💬 Comments