skip to Main Content

NestJS allows us to read .env file through ConfigModule and I can do that easily in my modules with code like following

@Module({
  imports: [ConfigModule.forRoot()],
  providers: [
    NVFullNameSearchService,
    NVPartialNameSearchService,
    NVPersistService,
  ],
  controllers: [NvController],
})

But above code is more to deal within modules, how can I read content from .env file in main.ts. Say I need to set port and host for my Redis service?

const microserviceOptions = {
  name: 'plscorecard',
  transport: Transport.REDIS,
  options: {
    url: 'redis://localhost:6379',
  },
};
async function bootstrap() {
  const app = await NestFactory.createMicroservice(
    NVModule,
    microserviceOptions,
  );
  app.listen(() => {
    logger.log('NameVerification Redis microservice is listening ... ');
  });
}
bootstrap();

As you can see app is yet to be created in this case. Should I directly use dotenv? As you’d expect in any enterprise environment, I have different env files for DEV, QA, UAT and Production. What’s the easiest/right way to achieve it?

5

Answers


  1. Chosen as BEST ANSWER

    Thanks for all of your support. Here's how I fixed it

    **app.module.ts**
    import { Module } from '@nestjs/common';
    import { AppController } from './app.controller';
    import { AppService } from './app.service';
    import { ConfigModule } from '@nestjs/config';
    
    @Module({
      imports: [
        ConfigModule.forRoot({
          isGlobal: true,
          envFilePath: `config/${process.env.NODE_ENV}.env`,
        }),
      ],
      controllers: [AppController],
      providers: [AppService],
    })
    export class AppModule {}
    

    With the module now having the right setting, only thing left on this is to invoke it from main.ts in a more unconventional but documented way

    **main.ts**
    import { Logger } from '@nestjs/common';
    import { NestFactory } from '@nestjs/core';
    import { Transport } from '@nestjs/microservices';
    import { AppModule } from './app.module';
    import { ConfigService } from '@nestjs/config';
    
    async function bootstrap() {
      const logger = new Logger('main');
      const app = await NestFactory.create(AppModule);
      const configService = app.get(ConfigService);
      const REDIS_HOST = configService.get<string>('REDIS_HOST');
      const REDIS_PORT = configService.get<number>('REDIS_PORT');
      const microserviceOptions = {
        transport: Transport.REDIS,
        options: {
          url: `redis://${REDIS_HOST}:${REDIS_PORT}`,
        },
      };
      app.connectMicroservice(microserviceOptions);
      const PORT = configService.get<number>('PORT');
      const environment = configService.get<string>('NODE_ENV');
      const title = configService.get<string>('ENVIRONMENT_TITLE');
      await app.listen(PORT);
      logger.log(
        `${environment}, Microservice ready to receive Redis messages in PORT - ${PORT}n Environment - ${title}`,
      );
    }
    bootstrap();
    

  2. The easiest solution is actually to just import dotenv and initiialize it immediately after. It is particulary important that these are the first two things you do in your main.ts, like this:

    import * as dotenv from 'dotenv';
    dotenv.config();
    import ...
    ...
    async function bootstrap(){
    ...
    }
    

    No config module is needed to access variables in a .env file after doing that.

    Login or Signup to reply.
  3. You can avoid using dotenv using your configuration service in your main.ts with app.get() method.

    import { ConfigurationService } from './core/configuration/configuration.service';
    
    async function bootstrap() {
      const configurationService = app.get(ConfigurationService);
    
      await app.listen(configurationService.expressPort);
    }
    

    For more informations, mind reading the documentation about using configuration in your main.ts

    Login or Signup to reply.
  4. dotenv is the only true answer.

    Why using a such complicated thing such as @nestjs/config which encapsulate it but is useless on reel config level, ex: trying to config MongooseModule in app module with .env file is not working with @nest/config but fully working with dotenv.

    .env files are often meant to be used right a main script start.

    The real question is why Nodejs does not import natively .env files?

    Login or Signup to reply.
  5. I like to handle env var loading in a completely decoupled way and prevent involving dotenv or similars to the Nest execution.

    With "env-cmd" npm package (https://www.npmjs.com/package/env-cmd, which you could install as a devDependency) you can specify the .env file you want to load before executing NestJS:

    package.json scripts section:

    {
      // For production
      "start": "nest start",
    
      // For local development
      "start:dev": "env-cmd -f ./.env nest start"
    }
    

    Additionally, you can make custom validations for your envvars during application bootstrap in your main.ts file, for example, preventing the server to start if your env vars are not set.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search