Create Custom Database Module in NestJS with TypeORM MySQL/PostgreSQL
Tags: nestjs, typeorm, mysql, postresql
Published: 2021-07-01 01:27:03

# Intro
First, Check out these articles for
Custom Database Setup for Sequelize: https://www.freecodecamp.org/news/build-web-apis-with-nestjs-beginners-guide/
Custom Database Setup for MongoDB: https://dev.to/10xtarun/create-custom-database-module-in-nestjs-4kim
I got a lot of inspiration from these articles especially from the first by Victor


# Setup Project 
We Create new nest project as,
```
$ nest new custom-db-project
```

We will also install all we need,
```
$ npm install --save @nestjs/typeorm @nestjs/config typeorm mysql2 dotenv

```

Now generate the custom database module as,
```
$ nest generate module core/database
```
...
Let's Code


## Database Interface
Inside the database folder, create an interfaces folder, then create a **dbConfig.interface.ts** file inside it. This is for the database configuration interface.

Each of the database environments should optionally have the following properties. 

```
export interface IDatabaseConfigAttributes {
    username?: string;
    password?: string;
    database?: string;
    host?: string;
    port?: number;
    type?: string;
    urlDatabase?: string;
    entities?: string[];
    migrationsTableName?: string;
    migrations?: string[];
    cli?: {
        migrationsDir?: string;
    }
    synchronize?: boolean;
}

export interface IDatabaseConfig {
    development: IDatabaseConfigAttributes;
    test: IDatabaseConfigAttributes;
    production: IDatabaseConfigAttributes;
}
```


##Database Configuration
Now, let’s create a database environment configuration. Inside the database folder, create a **database.config.ts** file. 

```
import * as dotenv from 'dotenv';
import { IDatabaseConfig } from './interfaces/dbConfig.interface';

dotenv.config();

let entities = [__dirname + '/**/*.entity{.ts,.js}']

let migrationsDir = 'src/migration';
let migrations = [migrationsDir + '/*.ts']

export const databaseConfig: IDatabaseConfig = {
    development: {
        username: process.env.DB_USER,
        password: process.env.DB_PASS,
        database: process.env.DB_NAME_DEVELOPMENT,
        host: process.env.DB_HOST,
        port: +process.env.DB_PORT,
        type: process.env.DB_DIALECT,
        entities: entities,
        migrationsTableName: process.env.DB_MIGRATION_TABLE_NAME,
        migrations: migrations,
        cli: {
            migrationsDir: migrationsDir
        },
        synchronize: true
    },
    test: {
        username: process.env.DB_USER,
        password: process.env.DB_PASS,
        database: process.env.DB_NAME_TEST,
        host: process.env.DB_HOST,
        port: +process.env.DB_PORT,
        type: process.env.DB_DIALECT,
        entities: entities,
        migrationsTableName: process.env.DB_MIGRATION_TABLE_NAME,
        migrations: migrations,
        cli: {
            migrationsDir: migrationsDir
        },
        synchronize: true
    },
    production: {
        username: process.env.DB_USER,
        password: process.env.DB_PASS,
        database: process.env.DB_NAME_PRODUCTION,
        host: process.env.DB_HOST,
        port: +process.env.DB_PORT,
        type: process.env.DB_DIALECT,
        entities: entities,
        migrationsTableName: process.env.DB_MIGRATION_TABLE_NAME,
        migrations: migrations,
        cli: {
            migrationsDir: migrationsDir
        },
        synchronize: true
    },
};
```

The environment will determine which configuration should be used.

##.env file
On our project root folder, create a **.env** file

```
DB_HOST=localhost
DB_PORT=3306
DB_USER=database_user_name
DB_PASS=database_password
DB_DIALECT=postgres
DB_NAME_TEST=test_database_name
DB_NAME_DEVELOPMENT=development_database_name
DB_NAME_PRODUCTION=production_database_name
DB_MIGRATION_TABLE_NAME=migration

```

Don't forget to add .env to your **.gitignore** file. 

## Import the @nestjs/config 
Import the @nestjs/config into your app root module:

```
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { DatabaseModule } from './core/database/database.module';

@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true }),
    DatabaseModule
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}
```

**Victor Pointed out that Setting the ConfigModule.forRoot({ isGlobal: true }) to isGlobal: true will make the .env properties available throughout the application.**

##Database Provider
Let’s create a database provider. Inside the database folder, create a file called **database.providers.ts**.

The core directory will contain all our core setups, configuration, shared modules, pipes, guards, and middlewares.

In the database.providers.ts let's add

```
import { TypeOrmModule } from '@nestjs/typeorm';
import { TYPEORM ,DEVELOPMENT, TEST, PRODUCTION } from '../constants';
import { databaseConfig } from './database.config';

export const databaseProviders = [{
    provide: TYPEORM,
    useFactory: async () => {
      let config;
      switch (process.env.NODE_ENV) {
      case DEVELOPMENT:
         config = databaseConfig.development;
         break;
      case TEST:
         config = databaseConfig.test;
         break;
      case PRODUCTION:
         config = databaseConfig.production;
         break;
      default:
         config = databaseConfig.development;
      }

      const typeOrm = TypeOrmModule.forRoot(config);
      
      return typeOrm
    },
}];

```

Here, the application decides what environment we are currently running on and then chooses the environment configuration.


Best practice: It is a good idea to keep all string values in a constant file and export it to avoid misspelling those values. You'll also have a single place to change things.

Inside the core folder, create a constants folder and inside it create an index.ts file. Paste the following code:

```
export const TYPEORM = 'TYPEORM';
export const DEVELOPMENT = 'development';
export const TEST = 'test';
export const PRODUCTION = 'production';
```


I hope this article helps someone. Check out the article by Victor to get started with Nestjs