6

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?

Krishnan Sriram
  • 5,037
  • 5
  • 21
  • 31
  • did you ever tried the approach that [nestjs's docs covers](https://docs.nestjs.com/techniques/configuration)? – Micael Levi Mar 02 '21 at 23:44
  • 1
    Does this answer your question? [How to use config module on main.ts file](https://stackoverflow.com/questions/57127512/how-to-use-config-module-on-main-ts-file) – Jay McDoniel Mar 02 '21 at 23:46
  • Nest has a doc session for that: https://docs.nestjs.com/techniques/configuration#using-in-the-maints – lsouza Mar 03 '21 at 07:29

6 Answers6

13

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();
Krishnan Sriram
  • 5,037
  • 5
  • 21
  • 31
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

Hugo Sohm
  • 2,872
  • 4
  • 23
  • 40
  • I prefer this approach as well. However, if `ConfigurationService` doesn't load the env vars while initialising (in the constructor), this won't work. The `port` is assigned when the Nest core bootstrapping starts (1st step) and other lifecycle events come after that. So if one is reading the env vars onModuleInit or onApplicationBootstrap, `expressPort` would be `NaN`. To get it to work, either call a method of the `configurationService` to load and assign env vars, so calling `configurationService.expressPort` gives us the port#. Or use `ConfigService` as the answer suggests. – sandiejat Jul 26 '23 at 22:45
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.

Ele
  • 154
  • 1
  • 10
1
import { ConfigService } from "@nestjs/config";
async function bootstrap() {
  const configService = app.get(ConfigService);
  const port = configService.get("PORT") || 8000;
  await app.listen(port);
}
0

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.

-1

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?

Tyler2P
  • 2,324
  • 26
  • 22
  • 31