# How to setup TypeORM migrations in a NestJS project

### Motivation

[TypeORM](https://typeorm.io/) is the most mature Object Relational Mapper (ORM) for TypeScript and JavaScript. Since it's written in TypeScript, it integrates well with the [NestJS](https://nestjs.com/) framework. For integrating with SQL and NoSQL databases, Nest provides the `@nestjs/typeorm` package. [Here](https://docs.nestjs.com/techniques/database#typeorm-integration) the official documentation of NestJS has clear instructions on how to integrate TypeORM with it. However, they skipped the details on [how to setup the migrations](https://docs.nestjs.com/techniques/database#migrations) and forwarded them to the TypeORM documentation for [migration](https://typeorm.io/migrations#creating-a-new-migration), which is very generic and not aligned with NestJS. That is the motivation of this article. In this article, I'll show how to setup migrations in a NestJS project using TypeORM. Buckle up and let's get started.

### Initial project setup

Let's initialize our project using [Nest CLI](https://docs.nestjs.com/cli/overview).

```bash
nest new nest-typeorm
```

Navigate to the project folder and install the necessary dependencies. In this example, I am using [PostgreSQL](https://www.postgresql.org/), therefore I have added `pg` as a dependency.

```bash
cd nest-typeorm
npm install --save @nestjs/typeorm typeorm pg
```

### Database connection

Let's create a separate Nest module for handling database-related tasks.

```bash
nest g module db
```

Create the `data-source.ts` file inside the `src/db` directory. This file will contain database connection configurations.

```typescript
// src/db/data-source.ts
import { config } from 'dotenv';
import { DataSourceOptions } from 'typeorm';

config();

export const dataSourceOptions: DataSourceOptions = {
  type: 'postgres',
  host: process.env.DB_HOST,
  port: +process.env.DB_PORT,
  username: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_NAME,
  entities: [],
};
```

Use this `dataSourceOptions` for setting up TypeOrmModule inside the DbModule that we generated using Nest CLI.

```typescript
// src/db/db.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { dataSourceOptions } from './data-source';

@Module({
  imports: [TypeOrmModule.forRoot(dataSourceOptions)],
})
export class DbModule {}
```

Now if you run the project using `npm run start:dev` command, it should be able to connect to the database. However, you have to make sure the database server is up and running and the database with the name that we specified in the `data-source` file is already created.

### Generate an entity

Generate `users` resource using the CLI.

```bash
nest g resource resource/users
```

It will generate the `users` module, controller, service, DTOs and entity file inside `src/resource/users` directory.

Let's update the `user.entity.ts` file and add some columns there.

```typescript
// src/resources/users/entities/user.entity.ts
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ name: 'first_name' })
  firstName: string;

  @Column({ name: 'last_name' })
  lastName: string;
}
```

Now we need to create the migration for creating the user table with the id, first\_name, last\_name columns.

### Generate the migration

Migration in TypeORM is just a class that implements `MigrationInterface` from the `typeorm` package. It needs to implement the `up` and `down` methods. The `up` method executes the query for applying new changes in the database. On the other hand, `down` method executes the query to revert the changes that was applied by the `up` method.

It is possible to implement a migration by manually implementing the `MigrationInterface`. However, TypeORM provides a nice [CLI](https://typeorm.io/using-cli) to generate that automatically based on the data-source and entity.

Now the first thing is, we need to make TypeORM aware that we have an entity called `user`. To do that, we need to update the `entities` array in the data-source file. The entities array accepts both entity classes and directories from where entities need to be loaded. Directories support glob pattern. In our case, we want every entity from our resources directory to be loaded.

```typescript
// src/db/data-source.ts
...
export const dataSourceOptions: DataSourceOptions = {
  ...
  entities: ['src/resources/**/*.entity.ts'],
};
```

Though we are working with typescript, the above code will throw `Cannot use import statement outside a module` error. To make it work smoothly it is safe to use `.js` files. Our build command will generate the javascript files during build time and put them into `/dist` directory. We can simply use that path here.

```typescript
// src/db/data-source.ts
...
export const dataSourceOptions: DataSourceOptions = {
  ...
  entities: ['dist/resources/**/*.entity.js'],
};
```

At this point, our project is ready for generating the first migration. We will use [TypeORM CLI](https://typeorm.io/using-cli) to generate the migration file. The command for generating a migration file from a data-source is like this.

```bash
npx typeorm migration:generate -d path/to/datasource path/to/Migration
```

However, we are using entity path from `dist` directory. That means, we need to run the build command before using the typeorm command. We can combined those commands like this.

```bash
npm run build && npx typeorm migration:generate -d path/to/datasource path/to/Migration
```

Let's add a script in our `package.json` file combining these commands.

```json
// package.json
{
  ...
  "scripts": {
    ...
    "migration:generate": "npm run build && npx typeorm migration:generate -d ./dist/db/data-source.js",
  }
}
```

Notice that, we have added the path to data-soure file in the script but we omitted the path to migration file. We want to pass that dynamically from the command line when we invoke the script.

Let's invoke the script.

```bash
npm run migration:generate src/db/migrations/create-user-table
```

Once we execute this command in the terminal it will generate the migration file in the `src/db/migrations` directory. The file name will be something like `<timestamp>-create-user-table.ts`

If you open the migration file you can see the code like below.

```typescript
// src/db/migrations/<timestamp>-create-user-table.ts
import { MigrationInterface, QueryRunner } from "typeorm";

export class CreateUserTable1690462207991 implements MigrationInterface {
    name = 'CreateUserTable1690462207991'

    public async up(queryRunner: QueryRunner): Promise<void> {
        await queryRunner.query(`CREATE TABLE "user" ("id" SERIAL NOT NULL, "first_name" character varying NOT NULL, "last_name" character varying NOT NULL, CONSTRAINT "PK_cace4a159ff9f2512dd42373760" PRIMARY KEY ("id"))`);
    }

    public async down(queryRunner: QueryRunner): Promise<void> {
        await queryRunner.query(`DROP TABLE "user"`);
    }

}
```

### Run the migration

The migration file is generated. Now we need to execute it to update our database structure.

Before using the `migration:run` command from TypeORM CLI we need to update the `dataSourceOptions` and add `migrations` array to tell TypeORM from where it should read the migration files.

```typescript
// src/db/data-source.ts
...
export const dataSourceOptions: DataSourceOptions & SeederOptions = {
  ...
  migrations: ['dist/db/migrations/*.js'],
};
```

We have used the glob pattern to pick migration files from the `dist` directory (similar to `entities` array that we added before). Therefore, we must build the project before running the migration command. Same as before, we can combine the build and migration commands in the `package.json` file.

Let's add the script to run the migration in our `package.json` file.

```json
// package.json
{
  ...
  "scripts": {
    ...
    "migration:run": "npm run build && npx typeorm migration:run -d ./dist/db/data-source.js",
  }
}
```

Run the script through the terminal.

```bash
npm run migration:run
```

If you check your database now, you can see the `user` table is created.

### Conclusion

We have learned how to set up migration in a NestJS project using TypeORM.

You can find the full project here:  
[https://github.com/mazid1/nestjs-typeorm/tree/feature/migration](https://github.com/mazid1/nestjs-typeorm/tree/feature/migration)

In the next article, I will write about [how to seed test data using TypeORM.](https://blog.mazedulislam.com/how-to-seed-database-using-typeorm-in-a-nestjs-project)

---

I'm open for a remote full-time/contract/freelance job for the position of Full-stack Software Engineer. If you are hiring, ping me at **mazidmailbox@gmail.com**
