Sling Academy
Home/Node.js/NestJS: How to Use ConfigService with TypeOrmModule

NestJS: How to Use ConfigService with TypeOrmModule

Last updated: December 31, 2023

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.

Next Article: How to handle form-data in NestJS

Previous Article: How to mock a service in NestJS unit tests

Series: Nest.js Tutorials: From Basics to Advanced

Node.js

You May Also Like

  • NestJS: How to create cursor-based pagination (2 examples)
  • Cursor-Based Pagination in SequelizeJS: Practical Examples
  • MongooseJS: Cursor-Based Pagination Examples
  • Node.js: How to get location from IP address (3 approaches)
  • SequelizeJS: How to reset auto-increment ID after deleting records
  • SequelizeJS: Grouping Results by Multiple Columns
  • NestJS: Using Faker.js to populate database (for testing)
  • NodeJS: Search and download images by keyword from Unsplash API
  • NestJS: Generate N random users using Faker.js
  • Sequelize Upsert: How to insert or update a record in one query
  • NodeJS: Declaring types when using dotenv with TypeScript
  • Using ExpressJS and Multer with TypeScript
  • NodeJS: Link to static assets (JS, CSS) in Pug templates
  • NodeJS: How to use mixins in Pug templates
  • NodeJS: Displaying images and links in Pug templates
  • ExpressJS + Pug: How to use loops to render array data
  • ExpressJS: Using MORGAN to Log HTTP Requests
  • NodeJS: Using express-fileupload to simply upload files
  • ExpressJS: How to render JSON in Pug templates