Solutions

Migrations with TypeORM in NestJs

Migrations are a crucial part of database management and versioning in NestJS applications using TypeORM. TypeORM provides migration support to help you manage database schema changes over time.

Why We Need Migrations in NestJs ?

As we all know that NestJs provide auto-sync for our entity changes to the database, then the first question that was raised in our head that why we need migration? 

So, the answer is that we can use auto-sync functionality, but in some cases when our application is Live, and we have data in our database, then some direct modifications in our database might generate issues. So it is Unsafe to use synchronize on production.

Advantages

  • We can run migration whenever we need.
  • Reduce error generation on production.
  • We can generate migration files from entity changes directly. We don’t need to write migration files.
  • This is particularly useful when working in teams or deploying updates to production systems without disrupting existing data.
  • Each migration file represents a specific set of changes, making it easier to track and manage schema modifications over time.

Disadvantage

  • We need to generate migration files for every changes in our entity. After that we need to run it to alter database.
  • If you’re new to migrations or TypeORM, there may be a learning curve involved in understanding the concepts and best practices associated with migrations. This can slow down initial development and require additional effort to grasp the migration workflow.
  • When performing database schema changes, there is always a risk of data loss if not handled carefully. Modifying or deleting columns, tables, or relationships in migrations without proper backup strategies or safeguards can lead to unintentional data loss

Example

Suppose you have an entity named Student something like this:

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

}

Now you need to alter “name” column with “student_name” then you need to create a migration file with the below SQL query

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

TypeORM provides such functionality that you can store such queries and execute them to alter your database. This functionality is migrations.

How to Create New Migrations?

Before creating migrations you need to set up your TypeORM config file something like:

{
 "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}"
 ]
}

First of all, you need to close auto sync by setting “synchronize”: false

Then you need to specify migration files path in “cli”: {“migrationsDir”: “src/migrations”}, where all your migration files will generate.

While running migrations it will take files from “migrations” : [“src/migrations/*.ts”] path.

Also, we need to add a script for TypeORM in package.json file like:

"TypeORM": "ts-node ./node_modules/TypeORM/cli.js -f ./ormconfig.json"

After setting the config file you need to create a new migration file with: TypeORM migration:create -n PostRefactoring

This command will generate a new file in src folder like:

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

This file has contain two methods “up” and “down”. “up” is where you need to write your new SQL changes and “down” is used to revert those changes.

Now to alter our column we need to write query something like:

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"`);
   }
}

Run Migration

To run all migrations we need to execute the command:

npm run TypeORM migration:run

It will execute the file and alter the column of the student’s table.

Now, if we follow this process then we need to write queries for every single change. And execute migrations every time. But TypeORM provides functionality to generate migration automatically from entity changes.

For doing that you just need to run the below command:

npm run TypeORM migration:generate -- -n MigrationName

This command will generate all new changes in entities that are not in the database. So you can generate files and make changes in the database by running migrations.

Conclusion

Migrations are an essential part of managing database schemas in NestJS applications using TypeORM. They offer a structured approach to handle changes, ensuring data integrity and preventing disruptions in production environments. By utilizing migrations, developers can maintain control over their database structure while minimizing risks associated with direct modifications.

This practice not only streamlines collaboration in team settings but also safeguards against potential data loss. As you continue to build and scale your applications, incorporating a robust migration strategy will be key to maintaining a reliable and efficient database system.

Ready to enhance your NestJS application with efficient database migrations? Contact us today to discuss your project and how we can support your development journey!

Recent Posts

  • OTA

The Rise of Dynamic Packaging in OTA

Using dynamic packaging technology, one can encapsulate flights, accommodation, cars,…

  • UI/Ux Design

Unlocking Digital Success with UX/UI Design

In today’s contemporary era of accelerated digital evolution, the importance…

  • UI/Ux Design

Why UI Design is Important for Your Website? A Step Towards Way Superior UX

The fact is that in today’s internet environment the only…