Sling Academy
Home/Node.js/NestJS: Configuration and Environment Variables

NestJS: Configuration and Environment Variables

Last updated: January 01, 2024

Introduction

Mastering configuration management is critical for building scalable, maintainable, and adaptable web applications. This guide delves into NestJS, a progressive Node.js framework, outlining vital practices to handle configuration and environment variables effectively, thus laying the groundwork for robust and secure applications.

Setting up Configuration

Begin your journey with the installation of the configuration package:

$ npm install @nestjs/config

Then, import the ConfigModule in your app module:

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

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

This instantiates the ConfigModule globally, affording you access to environment variables via injection throughout your application.

Utilizing Dotenv Files

Introduce a .env file at your project root:

DB_HOST=localhost
DB_PORT=5432

Environment-specific variables can be managed with multiple dotenv files, e.g. .env.development, .env.test, and so on.

The ConfigModule automatically loads variables based on your NODE_ENV:

ConfigModule.forRoot({
  envFilePath: ".env." + process.env.NODE_ENV,
})

Typed Configuration Service

Create a typed configuration service to ensure the safe use of environment variables:

import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';

@Injectable()
export class AppConfigService {
  constructor(private configService: ConfigService) {}

  get databaseHost(): string {
    return this.configService.get<string>('DB_HOST');
  }

  // Other configuration methods
}

This service can now be injected wherever it’s needed, offering safe access to the variables with the correct type.

Validation Schema

Add Joi or any other validation library to aid in the creation of validation schemas for your environment configurations:

import * as Joi from 'joi';

ConfigModule.forRoot({
  validationSchema: Joi.object({
    DB_HOST: Joi.string().required(),
    DB_PORT: Joi.number().default(5432),
  }),
})

The schema ensures all required variables are set and optionally assigns defaults.

Configuration Namespaces

Isolate configurations into namespaces to maintain organization:

ConfigModule.forRoot({
  load: [databaseConfig],
})

export const databaseConfig = () => ({
  database: {
    host: process.env.DB_HOST,
    port: process.env.DB_PORT,
  },
});

Access these namespaced settings within services using the get() method with the path to the configuration key:

const dbConfig = this.configService.get('database');

Async Configuration

For asynchronous operations, the ConfigModule supports async methods:

import { ConfigService } from '@nestjs/config';
import { DatabaseModule } from './database/database.module';

@Module({
  imports: [
    DatabaseModule,
    ConfigModule.forRootAsync({
      useClass: AppConfigService,
    }),
  ],
})
export class AppModule {}

This technique is beneficial if configs need to be fetched from a service, such as a database or API.

Environment Configuration for Modules

It’s often useful to have module-specific configurations:

import { ConfigModule, ConfigService } from '@nestjs/config';
import { Module } from '@nestjs/common';

@Module({
  imports: [
    ConfigModule.forFeature(databaseConfig),
  ],
})
export class DatabaseModule {}

Now databaseConfig is accessible solely within the DatabaseModule, helping to encapsulate configuration details.

Using Config in Other Services

Here’s an example of a service using the AppConfigService to access its configuration:

import { Injectable } from '@nestjs/common';
import { AppConfigService } from './app-config.service';

@Injectable()
export class SomeService {
  constructor(private config: AppConfigService) {
    const dbHost = this.config.databaseHost;
    // Use dbHost
  }
}

Custom Configuration Files

For complex setups, create custom configuration files and import them selectively:

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

@Module({
  imports: [
    ConfigModule.forRoot({
      load: [customConfig],
    }),
  ],
})
export class CustomModule {}

Best Practices

  • Security: Never commit sensitive environment variables to version control. Use secrets management systems like Vault or environment management tools.
  • Validation: Always validate environment variables to prevent runtime errors.
  • Documentation: Clearly document all environment variables for ease of maintenance and collaboration.

Conclusion

Effective configuration management within NestJS applications is paramount to developing secure, efficient, and manageable web services and apps. By applying the best practices covered in this guide, such as segregating configuration, validating environment variables, and leveraging the power of ConfigModule, developers are well-equipped to build superior NestJS applications.

Next Article: NestJS & MongoDB: A Simple CRUD Example

Previous Article: How to Use Dependency Injection in NestJS

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