NestJS: How to Use ConfigService with TypeOrmModule

Updated: December 31, 2023 By: Guest Contributor Post a comment

Introduction

Integrating NestJS’s ConfigService with TypeOrmModule simplifies database configuration management, by allowing the application to adapt seamlessly to different environments while enforcing type safety and embracing modularity.

Getting Started

Before diving into the integration of ConfigService with TypeOrmModule, ensure that you have a NestJS project setup. If you don’t, you can create one by running:

nest new project-name

Next, install the required dependencies for TypeORM and configuration:

npm install @nestjs/typeorm typeorm
npm install @nestjs/config

Setting up ConfigModule

To begin, import ConfigModule in your application:

import { ConfigModule } from '@nestjs/config';

@Module({
    imports: [ConfigModule.forRoot()],
    // ...
})
export class AppModule {}

This will enable the usage of environment variables throughout your application. Now onto configuring the database connection.

Basic Database Connection Setup

Create a configuration file, e.g., .env, at the root of your project that stores your database connection settings:

DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_USERNAME=root
DB_PASSWORD=root
DB_DATABASE=test_db

Now, configure TypeOrmModule to use ConfigService to dynamically set the database options:

import { TypeOrmModule } from '@nestjs/typeorm';
import { ConfigModule, ConfigService } from '@nestjs/config';

@Module({
  imports: [
    TypeOrmModule.forRootAsync({
      imports: [ConfigModule],
      useFactory: (configService: ConfigService) => ({
        type: configService.get('DB_CONNECTION'),
        host: configService.get('DB_HOST'),
        port: configService.get('DB_PORT'),
        username: configService.get('DB_USERNAME'),
        password: configService.get('DB_PASSWORD'),
        database: configService.get('DB_DATABASE'),
        entities: [__dirname + '/**/*.entity{.ts,.js}'],
        synchronize: true,
      }),
      inject: [ConfigService],
    }),
  ],
  // ...
})
export class AppModule {}

This setup uses a factory function to pass in the ConfigService and then use it to access the necessary configuration values.

Advanced Configuration

To further enhance your configuration, you can define custom environment variables based on the current NODE_ENV, leverage schemas for validation, and more.

Environment Specific Configuration

import { ConfigModule } from '@nestjs/config';
import configuration from './config/configuration';

ConfigModule.forRoot({
    load: [configuration],
    envFilePath: ".env." + process.env.NODE_ENV,
});

With the above code, you can have multiple .env files like .env.development, .env.test, and .env.production that will be loaded depending on the NODE_ENV value.

Validating Configuration

NestJS’s ConfigModule allows you to define validation schemas using class-validator. Here’s a quick example of how to set up validation to ensure all your environment variables are correctly set:

import * as Joi from 'joi';

ConfigModule.forRoot({
    validationSchema: Joi.object({
        DB_CONNECTION: Joi.string().required(),
        DB_HOST: Joi.string().required(),
        // More validations here...
    })
});

Misspelled or missing environment variables would cause the application to throw an error early on startup, promoting fewer runtime issues.

Integrating with Modules: Multiple Databases

In cases where you need to connect to multiple databases, you can leverage this setup with slight modifications to differentiate between different connections:

import { TypeOrmModule } from '@nestjs/typeorm';
import { ConfigService } from '@nestjs/config';

@Module({
 imports: [
 TypeOrmModule.forRootAsync({
 imports: [...],
 useFactory: async (configService: ConfigService) => [{
    name: 'connectionName1', // Specify connection name here
    // Other options as before
  }, {
    name: 'connectionName2', // Another connection name
    // Other options
  }],
 inject: [ConfigService]
 }),
 // Your other imports here...
 ]
})
export class AppModule {}

This pattern allows you to create named connections that can be injected into your services or repositories.

Conclusion

The ConfigService integration with TypeOrmModule in NestJS brings several benefits, including scalability and environment adaptability. By following best practices and leveraging advanced configurations, you’ll have a robust setup for handling database connections in your NestJS applications.