Migrations with TypeORM in NestJs

Migrations with TypeORM in NestJs

Why Do We Need Migrations in NestJs?

NestJs provides an auto-sync feature that automatically updates the database when entity changes occur. Given this, you might wonder why migrations are necessary.

The reason is that while auto-sync can be convenient, it can become risky in production environments. When your application is live and contains actual data, direct modifications to the database could lead to issues. This is why relying on synchronization in production is considered unsafe.

Advantages of Using Migrations

  • You can control when migrations are applied.
  • Reduces the risk of errors in production environments.
  • Migration files can be automatically generated from entity changes, so you don’t need to manually write them.

Disadvantages of Migrations

  • You need to generate and run migration files every time you make changes to your entities.

Example

Suppose you have an entity named Student:

import { BaseEntity, Column, Entity, PrimaryGeneratedColumn } from 'typeorm'; @Entity('students') export class Students extends BaseEntity { @PrimaryGeneratedColumn() id: string; @Column() name: string; @Column() marks: number; }

Now, if you want to rename the name column to student_name, you would create a migration file with the following SQL query:

ALTER TABLE "students" ALTER COLUMN "name" RENAME TO "student_name";

TypeORM allows you to store such queries and execute them later to modify the database. This process is known as migrations.

How to Create New Migrations

Before creating migrations, you need to configure your TypeORM settings like this:

{ "type": "postgres", "host": "postgres", "port": 5432, "username": "postgres", "password": "postgres", "database": "elite_opinio", "entities": [ "/usr/src/eliteopinio/backend/dist/@config/../**/entities/*.entity.{js,ts}" ], "synchronize": false, "migrations": [ "src/migrations/*.ts" ], "migrationsTableName": "migrations_TypeORM", "cli": { "migrationsDir": "src/migrations" }, "seeds": [ "/usr/src/eliteopinio/backend/dist/**/entities/*.seeder.{js,ts}" ], "factories": [ "/usr/src/eliteopinio/backend/dist/**/entities/*.factory.{js,ts}" ] }
  1. Disable Auto Sync: Set "synchronize": false to disable automatic syncing.
  2. Specify Migration Path: Define where your migration files will be stored: "cli": { "migrationsDir": "src/migrations" }.
  3. Add TypeORM Script: Update your package.json with a TypeORM script:
"TypeORM": "ts-node ./node_modules/typeorm/cli.js -f ./ormconfig.json"

Creating a New Migration File

After configuring TypeORM, you can create a new migration file with the command:

TypeORM migration:create -n PostRefactoring

This generates a new file in the src/migrations folder, which looks like this:

import { MigrationInterface, QueryRunner } from 'typeorm'; export class Student12345 implements MigrationInterface { public async up(queryRunner: QueryRunner): Promise<void> {} public async down(queryRunner: QueryRunner): Promise<void> {} }

The up method is where you write new SQL queries for changes, while the down method is used to revert them. For example, to add a new status column to the students table, you'd write:

import { MigrationInterface, QueryRunner } from 'typeorm'; export class Student12345 implements MigrationInterface { public async up(queryRunner: QueryRunner): Promise<void> { await queryRunner.query(`ALTER TABLE "students" ADD "status" boolean NOT NULL DEFAULT false`); } public async down(queryRunner: QueryRunner): Promise<void> { await queryRunner.query(`ALTER TABLE "students" DROP COLUMN "status"`); } }

Running Migrations

To run the migration, use the command:

npm run TypeORM migration:run

This will execute the file and modify the table as specified.

Automatically Generating Migrations

Instead of writing queries for every change, TypeORM allows you to generate migration files automatically from entity changes:

npm run TypeORM migration:generate -- -n MigrationName

This will detect changes that are not yet in the database and generate migration files to update the schema accordingly.

Conclusion

Migrations are particularly useful for live applications. For instance, if you introduce a new relationship in your entities and synchronization is enabled, data mismatches on the server might cause errors during deployment. As we've seen, migrations provide a safe and structured approach to updating database schemas.

Comments

Popular posts from this blog

Speeding Up Docker Build Times

Circular Dependencies in NestJS and How to Prevent Them

Function Components vs Class Components in React – With Examples