agentleFS
PackmindHubPackmindHub/packmind/.claude/skills/how-to-write-typeorm-migrations-in-packmind/SKILL.md

how-to-write-typeorm-migrations-in-packmind

Skill321 starsChanged 54 days agoApache-2.0View on GitHub

Write TypeORM migrations in the Packmind monorepo to manage and version database schema changes with consistent logging, reversible rollbacks, and shared helpers. Use this skill whenever creating or modifying database tables, columns, or foreign-key relationships — including any time schema changes need to be tracked, versioned, or rolled back. Invoke even if the user just says "add a column", "create a table", or "update the DB schema".

The file

We split this skill into the rules it gives an agent

9 rules. About 0 are common, 7 are distinctive, and 2 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈7

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Write TypeORM migrations in the Packmind monorepo to manage database schema changes effectively while ensuring proper logging and rollback …

    line 6
  2. Distinctive:

    When you need to create new database tables

    line 10
  3. Distinctive:

    When adding or modifying columns in existing tables

    line 11
  4. Distinctive:

    When creating or updating foreign key relationships

    line 12
  5. Distinctive:

    When making any database schema changes that need to be version controlled

    line 13
  6. Very specific:

    Use TypeORM Table class with shared helper columns (uuidMigrationColumn, timestampsMigrationColumns) from @packmind/shared to create new …

    line 79
  7. Distinctive:

    Use TableColumn class for adding individual columns or raw SQL for multiple columns.

    line 118
  8. Distinctive:

    Create foreign key relationships using TableForeignKey class with proper cascade behavior.

    line 154
  9. Distinctive:

    Always include comprehensive logging with PackmindLogger, wrap operations in try-catch blocks, write reversible migrations with …

    line 193

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Write TypeORM migrations in the Packmind monorepo to manage database schema changes effectively while ensuring proper logging and rollback capabilities.

When to Use

  • When you need to create new database tables
  • When adding or modifying columns in existing tables
  • When creating or updating foreign key relationships
  • When making any database schema changes that need to be version controlled

Context Validation Checkpoints

  • Have you identified the exact database schema changes needed?
  • Do you know the TypeORM column types for all fields?
  • Have you planned the rollback strategy (down method)?
  • Are you familiar with the shared migration utilities in @packmind/shared?

Recipe Steps

Step 1: Create Migration File Using TypeORM CLI

IMPORTANT: Always create migration files using the TypeORM CLI command. Never create migration files manually. The CLI automatically generates a timestamp prefix and sets up the basic structure.

# Create new migration file (TypeORM will automatically add timestamp)
npx typeorm migration:create packages/migrations/src/migrations/DescriptiveName

Step 2: Set Up Basic Migration Structure with Logging

Implement the migration class with PackmindLogger for comprehensive logging. Include try-catch blocks and log start, progress, completion, and any errors.

import { MigrationInterface, QueryRunner } from 'typeorm';
import { PackmindLogger, LogLevel } from '@packmind/shared';

export class YourMigrationName1234567890 implements MigrationInterface {
  private readonly logger = new PackmindLogger(
    'YourMigrationName1234567890',
    LogLevel.DEBUG,
  );

  public async up(queryRunner: QueryRunner): Promise<void> {
    this.logger.info('Starting migration: YourMigrationName');
    
    try {
      // Your migration logic here
      this.logger.info('Migration YourMigrationName completed successfully');
    } catch (error) {
      this.logger.error('Migration YourMigrationName failed', {
        error: error.message,
      });
      throw error;
    }
  }

  public async down(queryRunner: QueryRunner): Promise<void> {
    this.logger.info('Starting rollback: YourMigrationName');
    
    try {
      // Your rollback logic here
      this.logger.info('Rollback YourMigrationName completed successfully');
    } catch (error) {
      this.logger.error('Rollback YourMigrationName failed', {
        error: error.message,
      });
      throw error;
    }
  }
}

Step 3: Implement Table Creation Pattern

Use TypeORM Table class with shared helper columns (uuidMigrationColumn, timestampsMigrationColumns) from @packmind/shared to create new tables with consistent structure.

import { MigrationInterface, QueryRunner, Table } from 'typeorm';
import {
  timestampsMigrationColumns,
  uuidMigrationColumn,
} from '@packmind/shared/src/database/migrationColumns';

export class CreateYourTable1234567890 implements MigrationInterface {
  private readonly table = new Table({
    name: 'your_table',
    columns: [
      uuidMigrationColumn, // Standard UUID primary key
      {
        name: 'name',
        type: 'varchar',
      },
      {
        name: 'description',
        type: 'text',
        isNullable: true,
      },
      ...timestampsMigrationColumns, // created_at, updated_at
    ],
  });

  public async up(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.createTable(this.table);
  }

  public async down(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.dropTable(this.table);
  }
}

Step 4: Implement Column Addition Pattern

Use TableColumn class for adding individual columns or raw SQL for multiple columns. Always make new columns nullable initially for backward compatibility.

// Single column with TableColumn
import { MigrationInterface, QueryRunner, TableColumn } from 'typeorm';

export class AddColumnsToTable1234567890 implements MigrationInterface {
  public async up(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.addColumn(
      'your_table',
      new TableColumn({
        name: 'new_column',
        type: 'varchar',
        isNullable: true,
      }),
    );
  }

  public async down(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.dropColumn('your_table', 'new_column');
  }
}

// Multiple columns with raw SQL
public async up(queryRunner: QueryRunner): Promise<void> {
  await queryRunner.query(`
    ALTER TABLE "your_table" 
    ADD COLUMN "column1" varchar NULL,
    ADD COLUMN "column2" varchar NULL,
    ADD COLUMN "column3" varchar NULL
  `);
}

Step 5: Implement Foreign Key Pattern

Create foreign key relationships using TableForeignKey class with proper cascade behavior. Always handle foreign keys before dropping related tables.

import { MigrationInterface, QueryRunner, TableForeignKey } from 'typeorm';

export class AddForeignKey1234567890 implements MigrationInterface {
  private readonly foreignKey = new TableForeignKey({
    columnNames: ['parent_id'],
    referencedColumnNames: ['id'],
    referencedTableName: 'parent_table',
    onDelete: 'CASCADE',
  });

  public async up(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.createForeignKey('child_table', this.foreignKey);
  }

  public async down(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.dropForeignKey('child_table', this.foreignKey);
  }
}

Step 6: Run and Test Migrations

Execute migrations using npm scripts for both local development and Docker environments. Test both up and down migrations.

# Local development
npm run typeorm migration:run
npm run typeorm migration:revert
npm run typeorm migration:show

# Docker environment
npm run typeorm migration:run -- -d datasourceDocker.ts

Step 7: Follow Migration Best Practices

Always include comprehensive logging with PackmindLogger, wrap operations in try-catch blocks, write reversible migrations with corresponding down operations, use descriptive names with verbs (Add, Remove, Update, Create, Drop), and handle foreign key dependencies properly when dropping tables.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.