# How to seed database using TypeORM in a NestJS project

### Motivation

It is often required to seed a database with initial data during development. In a [NestJS](https://nestjs.com/) + [TypeORM](https://typeorm.io/) project, we can do that with the help of [typeorm-extension](https://typeorm-extension.tada5hi.net/).

### 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: ['dist/resources/**/*.entity.js'],
  synchronize: true, // do not set it true in production application
};
```

> Setting `synchronize: true` shouldn't be used in production - otherwise you can lose production data. You should use migration instead. I have an article on [How to setup TypeORM migrations in a NestJS project](https://blog.mazedulislam.com/how-to-setup-typeorm-migrations-in-a-nestjs-project).

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

Since we set `synchronize: true` in our datasource options, if we run this project using `npm start` command, it should create the `user` table in our database.

> The database should already be running in the specified host and port before running the app.

If the `user` table is created successfully then we can start working on the seeding part.

### Seeding

We are going to use [typeorm-extension](https://typeorm-extension.tada5hi.net/) for seeding our database. Let's install it first.

```bash
npm install typeorm-extension --save
```

Now we need a seeder class for seeding the `user` entity. `Seeder` interface is exported from `typeorm-extension`, we just need to implement it. Let's create the class in `src/db/seeds/user.seeder.ts` file.

```typescript
// src/db/seeds/user.seeder.ts
import { Seeder, SeederFactoryManager } from 'typeorm-extension';
import { DataSource } from 'typeorm';
import { User } from '../../resources/users/entities/user.entity';

export default class UserSeeder implements Seeder {
  public async run(
    dataSource: DataSource,
    factoryManager: SeederFactoryManager,
  ): Promise<void> {
    await dataSource.query('TRUNCATE "user" RESTART IDENTITY;');

    const repository = dataSource.getRepository(User);
    await repository.insert({
      firstName: 'Mazedul',
      lastName: 'Islam',
    });
  }
}
```

We have implemented the `run` method from the `Seeder` interface. When we execute the seed command using the `typeorm-extension` CLI, this run function will be executed. The `run` method has access to the `DataSource` and `SeederFactoryManager` instances, as they are passed as arguments.

At first, we truncate the `user` table and restart the identity sequence to make sure the first record will get ID 1. Then we get the user repository from the `dataSource` and insert our first user object into the table using the repository.

Now we need to tell the dataSource that we have this seeder class. To do that, let's update our `src/db/data-source.ts` file.

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

We have added `seeds` array into our `dataSourceOptions` object. Notice, we are using the glob pattern for pointing to the `seeds` directory inside the `dist/db/` directory. The glob pattern will not work if you point to the typescript files inside `src/db/seeds/` directory. Since our build command will generate the dist directory anyway, there is no harm using the `.js` files from there.

Now, add a script for seeding in the `package.json`.

```json
// package.json
{
  ...
  "scripts": {
    ...
    "seed": "npm run build && ts-node ./node_modules/typeorm-extension/dist/cli/index.js seed -d ./src/db/data-source.ts"
  }
}
```

In this command, we build the project first, then run the seed command from `typeorm-extension` with the help of `ts-node`.

> Note: using the `-d ./src/db/data-source.ts` we are passing the path to the datasource file to the seed command.

Let's invoke the script.

```bash
npm run seed
```

Once we execute the command the `user` table in the database should be populated with one user.

### Factories to generate bulk data

To generate random data for an entity, create a factory for the desired entity.

The factory callback provides an instance of the [**faker**](https://fakerjs.dev/guide/) library as a function argument, to populate the entity with random data.

Create a factory function in `src/db/factories/user.factory.ts` file.

```typescript
// src/db/factories/user.factory.ts
import { setSeederFactory } from 'typeorm-extension';
import { User } from '../../resources/users/entities/user.entity';

export default setSeederFactory(User, (faker) => {
  const user = new User();

  const sexFlag = faker.number.int(1);
  const sex: 'male' | 'female' = sexFlag ? 'male' : 'female';

  user.firstName = faker.person.firstName(sex);
  user.lastName = faker.person.lastName(sex);

  return user;
});
```

Now update the `user.seeder.ts` file and utilize this factory function for generating random users.

```typescript
// src/db/seeds/user.seeder.ts
...
export default class UserSeeder implements Seeder {
  public async run(
    dataSource: DataSource,
    factoryManager: SeederFactoryManager,
  ): Promise<void> {
    ...
    const userFactory = factoryManager.get(User);
    // save 1 factory generated entity, to the database
    await userFactory.save();

    // save 5 factory generated entities, to the database
    await userFactory.saveMany(5);
  }
}
```

Since we are using `SeederFactoryManager` instance to get the user factory, we need to update our `dataSourceOptions` and make it aware of the factory files.

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

Our factory setup is done. Run the `seed` command again.

```bash
npm run seed
```

Check the `user` table, it should have 1 hardcoded user and 6 more random users.

### Seed programmatically

It is also possible to seed the database from the codebase, without using the CLI commands. To do that, we need to get access to the `DataSource` instance. There is a function called [`runSeeders`](https://typeorm-extension.tada5hi.net/guide/seeding-api-reference.html#runseeder) exported from `typeorm-extension` which can be used to seed data programmatically. This is especially useful in e2e tests. You can seed your in-memory test database on-the-fly before each test. Probably I'll cover this in another article for testing a NestJS application.

### Conclusion

We have successfully configured SQL database seeding functionality using TypeORM and typeorm-extension package. We also get some insights on how to seed programmatically using `runSeeders` function provided by typeorm-extension.

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

In the next article, I'll write about how to test a NestJS application.

---

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**](mailto:mazidmailbox@gmail.com)
