ConfigurationModule

⭐ Interview Importance: LOW
⏱️ Revision Time: 5 min

The ConfigModule is the core of the @nestjs/config package. It handles the actual parsing of .env files and registers the ConfigService for dependency injection.

Overview

To use environment variables safely in NestJS, you don’t use dotenv directly. Instead, you import the ConfigModule into your root AppModule.

When the application boots, the ConfigModule locates your .env file, parses it, merges it with any existing system environment variables, and makes the resulting configuration available throughout your app.

Key Concepts

  • isGlobal: true: A crucial configuration option. Without it, you would have to import the ConfigModule into every single feature module that needs to read a variable.
  • envFilePath: Tells the module exactly where to look for the .env file if it’s not in the root directory.
  • load: Allows you to load custom configuration files (like JSON or YAML) instead of just .env files.

Code Examples

Standard Configuration

This is how 90% of NestJS applications initialize their configuration.

// app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { AppController } from './app.controller';

@Module({
  imports: [
    // Initialize the module using .forRoot()
    ConfigModule.forRoot({
      // Make it globally available so we don't have to import it in every module
      isGlobal: true, 
      
      // Ignore the .env file if we are running in production
      // (because production usually injects variables via the system, not a file)
      ignoreEnvFile: process.env.NODE_ENV === 'production',
      
      // Optionally specify a custom path (defaults to root .env)
      // envFilePath: '.env.development',
    }),
  ],
  controllers: [AppController],
})
export class AppModule {}

Loading Multiple Environment Files

If you need to cascade configurations (e.g., loading a base .env and then overriding it with .env.local), you can provide an array of paths.

ConfigModule.forRoot({
  // The module will parse these in order. 
  // If a variable exists in both, the FIRST file in the array wins.
  envFilePath: ['.env.local', '.env'],
})

Best Practices

  • Always use isGlobal: true: Unless you are building a highly specialized, isolated micro-architecture, there is almost no benefit to keeping the ConfigModule scoped. Make it global to reduce boilerplate.
  • Root Import Order: The ConfigModule.forRoot() should always be the very first item in your AppModule’s imports array. This ensures that the configuration is fully loaded and parsed before other modules (like TypeOrmModule) try to access the environment variables to connect to databases.