Migrations

A DataSource for the CLI

The TypeORM CLI needs its own DataSource file.

src/data-source.ts

import 'dotenv/config';
import { DataSource } from 'typeorm';

export default new DataSource({
  type: 'postgres',
  url: process.env.DATABASE_URL,
  entities: ['dist/**/*.entity.js'],
  migrations: ['dist/migrations/*.js'],
});
{
  "scripts": {
    "typeorm": "typeorm-ts-node-commonjs -d src/data-source.ts",
    "migration:generate": "npm run typeorm -- migration:generate src/migrations/$npm_config_name",
    "migration:run": "npm run build && typeorm -d dist/data-source.js migration:run",
    "migration:revert": "typeorm -d dist/data-source.js migration:revert"
  }
}

Generate, Review, Run

Example

After adding a sku column to Product:

npm run migration:generate --name=AddProductSku
npm run migration:run

Example output

Migration /app/src/migrations/1768471200000-AddProductSku.ts has been generated successfully.

query: SELECT * FROM "migrations" ORDER BY "id" DESC
0 migrations are already loaded in the database.
1 migrations were found in the source code.
1 migrations are new migrations must be executed.
query: START TRANSACTION
query: ALTER TABLE "products" ADD "sku" character varying(32)
query: CREATE UNIQUE INDEX "IDX_products_sku" ON "products" ("sku")
query: INSERT INTO "migrations"("timestamp", "name") VALUES ($1, $2) -- PARAMETERS: [1768471200000,"AddProductSku1768471200000"]
Migration AddProductSku1768471200000 has been executed successfully.
query: COMMIT

src/migrations/1768471200000-AddProductSku.ts

import { MigrationInterface, QueryRunner } from 'typeorm';

export class AddProductSku1768471200000 implements MigrationInterface {
  name = 'AddProductSku1768471200000';

  public async up(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(`ALTER TABLE "products" ADD "sku" character varying(32)`);
    await queryRunner.query(`CREATE UNIQUE INDEX "IDX_products_sku" ON "products" ("sku")`);
  }

  public async down(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(`DROP INDEX "public"."IDX_products_sku"`);
    await queryRunner.query(`ALTER TABLE "products" DROP COLUMN "sku"`);
  }
}

Tip: Always read a generated migration before running it. Renaming a column is generated as DROP + ADD, which loses data; edit it to RENAME COLUMN.