Managing Environment Variables in NestJS: A Guide to Custom Configurations
Tags: typescript, nestjs, programming, tutorial
Published: 2023-11-12 10:12:12

When developing applications with NestJS, managing environment variables efficiently is crucial for ensuring different configurations for development, staging, and production environments. In this blog post, we'll delve into setting up custom environment configurations in NestJS, focusing on the manage multiple environment, validation and accessing configuration

## 1. Before start

- install `@nestjs/config`
- install `joi` - for validation env

## 2. Setting Up the CustomConfigModule
Go to the `src` and create `config` folder and in it `config.module.ts`. The `CustomConfigModule ` is a crucial part of this setup, it imports and configures the `ConfigModule` from `@nestjs/config`. Here's a quick overview:

```typescript
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { configValidationSchema } from './config.schema';
import { CustomConfigService } from './config.service';

@Module({
  imports: [
    ConfigModule.forRoot({
      envFilePath: `${process.cwd()}/env/.env.${process.env.NODE_ENV}`,
      validationSchema: configValidationSchema,
      isGlobal: true,
      cache: true,
    }),
  ],
  providers: [CustomConfigService],
  exports: [CustomConfigService],
})
export class CustomConfigModule {}
```
This module dynamically sets the path to the environment file based on the `NODE_ENV` variable and uses `configValidationSchema` for validation.

## 3. Validating Environment Variables
Validation is key to ensuring that your environment variables are set correctly. Create `config.schema.ts` in `config` folder. I use Joi to validate and set defaults for these variables:

```typescript
import * as Joi from 'joi';

export const configValidationSchema = Joi.object({
  NODE_ENV: Joi.string()
    .valid('development', 'staging', 'production')
    .default('development'),
  PORT: Joi.number().default(3000),
});
```
This schema ensures that `NODE_ENV` is one of the specified strings and sets a default port if none is provided. Of course you can add as many env variables as you want eg. for database connection.

## 4. Accessing Configurations through CustomConfigService
To have nice intellisense and possibility to group our env variables I create `CustomConfigService`, defined in `config/config.service.ts`, is an injectable service that wraps the standard `ConfigService`:

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

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

  get app() {
    return {
      nodeEnv: this.configService.get<string>('NODE_ENV'),
      port: this.configService.get<number>('PORT'),
    };
  }
}

```
This service simplifies accessing the configured variables throughout your application.

## 5. Integrating with the Application
To utilize this configuration setup, you need to import `CustomConfigModule` in your `app.module.ts`. This makes the configurations and validations defined in the module available application-wide.

```typescript
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { CustomConfigModule } from './config/config.module';

@Module({
  imports: [CustomConfigModule],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}
```

## 6. Modifying the Start Script
Finally, modify the start script in `package.json` to include the `NODE_ENV` variable:

```json
"scripts": {
  "start": "NODE_ENV=development nest start"
}
```
This ensures that the application uses the correct environment settings when you start your NestJS app.

## Conclusion
Setting up custom environment configurations in NestJS can seem daunting initially, but with the right setup, like the `CustomConfigModule`, `configValidationSchema`, and `CustomConfigService`, you can ensure that your application runs smoothly in different environments. This setup not only promotes cleaner code but also enhances the overall maintainability of your application.