3

Does NestJS allow to have environment files in a similar way as Angular has?

In angular you have separate environment files which are mapped automatically depending on application environment (development, production, ...):

  • src/environments/environment.ts
  • src/environments/environment.prod.ts

Does @nestjs/config provide similar elegant and simple method to separate and manage environment variables? Unfortunately I cannot find a detailed explanation or usable example about this pattern for NestJS in official docs: https://docs.nestjs.com/techniques/configuration

Arnold Schrijver
  • 3,588
  • 3
  • 36
  • 65
Ferenc T
  • 766
  • 1
  • 6
  • 12

1 Answers1

0

Not familiar with Angular, so I don't know if it is as intuitive, but you should be looking at using Dynamic Modules for injecting your configuration.

The examples in the NestJS documentation already come quite close to what you want, except that they work on different .env files that are loaded directly in ConfigService.

Some coding required for your case, but you'll only have to do that once and can then reuse in any other NestJS project. Looking at the docs you can derive an Injectable() provider served by ConfigModule.register() which based on process.env.NODE_ENV is an instance of the appropriate environment class.

Or you can of course use the out-of-the-box example that loads .env directly. But that is not strongly-typed then.


Personally I use Joi-based Schema Validation and Configuration Namespaces and also define an interface for the config settings. Like the following example code:

env.schema.ts:

export const envSchema = Joi.object({

  NODE_ENV: Joi.string()
    .valid('development', 'production')
    .default('development'),

  EMAIL_VERIFICATION_SECRET: Joi.string().when('NODE_ENV', {
    is: 'production',
    then: Joi.required(),
    otherwise: Joi.optional().default('the_email_verification_secret'),
  }),
});

email.config.ts:

interface EmailConfig {
  verificationSecret: string;
}

export default registerAs('email', (): EmailConfig => ({
  verificationSecret: process.env.EMAIL_VERIFICATION_SECRET,
}));

notification.module.ts:

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

email-notification.service.ts:

@Injectable()
export class EmailNotificationService {
  private secret: string;

  constructor(
    @Inject(emailConfig.KEY)
    private mailConfig: ConfigType<typeof emailConfig>,
  ) {
    this.secret = this.mailConfig.verificationSecret;
  }
}

You don't have to use configuration namespaces of course, but it breaks the config up in just the chunks you need in a particular module. There is strong-typing via the interface, and with Joi your schema is both validated and adapted to the appropriate environment.

Arnold Schrijver
  • 3,588
  • 3
  • 36
  • 65