Search code examples
javascriptnode.jsenvironment-variablesnestjsdotenv

NestJS - How to use .env variables in main app module file for database connection


I am working on my first NestJS application, which was working fine with hardcoded database connecting string in app.module.ts.

But then as per our requirements, I had to pick the database config values from environment files. For that, I followed the configuration documentation on the nestjs documentation website - https://docs.nestjs.com/techniques/configuration

But the issue is that I need to use the .env variables inside the same file for database connection, which is failing.

Here is my original code that was working fine:

@Module({
  imports: [
    MongooseModule.forRoot(`mongodb+srv://myusername:[email protected]?retryWrites=true&w=majority&db=dbname`, { useNewUrlParser: true, dbName: 'dbname' }),
    ProductModule,
    CategoryModule,
  ],
  controllers: [
    AppController,
    HealthCheckController,
  ],
  providers: [AppService, CustomLogger],
})

Now, I wanted to pick those DB values from .env files which are like local.env, dev.env etc. depending on the environment. Now, my this code is not working:

@Module({
  imports: [
    ConfigModule.forRoot({ envFilePath: `${process.env.NODE_ENV}.env` }),
    MongooseModule.forRoot(`mongodb+srv://${ConfigModule.get('DB_USER')}:${ConfigModule.get('DB_PASS')}@myhost.net?retryWrites=true&w=majority&db=dbname`, { useNewUrlParser: true, dbName: 'dbname' }),
    ProductModule,
    CategoryModule,
  ],
  controllers: [
    AppController,
    HealthCheckController,
  ],
  providers: [AppService, CustomLogger],
})

Solution

  • 1. Keeping using ConfigModule

    You need to set NODE_ENV in npm scripts so that it can be used to load an env file based on the env.

    "scripts": {
      "start:local": "NODE_ENV=local npm run start"
      "start:dev": "NODE_ENV=dev npm run start"
    }
    

    Now you can just use the ConfigModule:

    @Module({
      imports: [
        ConfigModule.forRoot({ envFilePath: `${process.env.NODE_ENV}.env` }), 
    MongooseModule.forRoot(`mongodb+srv://${process.env.DB_USER}:${process.env.DB_PASS}@myhost.net?retryWrites=true&w=majority&db=dbname`, { useNewUrlParser: true, dbName: 'dbname' })
        ...
    })
    

    2. Using dotenv

    npm install dotenv
    

    Add some scripts to your package.json to set what env you are in.

    "scripts": {
      ...
      "start:local": "NODE_ENV=local npm run start"
      "start:dev": "NODE_ENV=dev npm run start"
    }
    

    Import dotenv in main.ts file. Make sure you do it at the top of the file.

    require('dotenv').config({ path: `../${process.env.NODE_ENV}.env` });
    

    3. Using env-cmd

    You can use env-cmd npm package.

    npm install env-cmd
    

    And add some commands for different envs in package.json, for example:

    "scripts": {
      ...
      "start:local": "env-cmd -f local.env npm run start"
      "start:dev": "env-cmd -f dev.env npm run start"
    }
    ...
    

    Now you can use the env variables, for example:

    MongooseModule.forRoot(`mongodb+srv://${process.env.DB_USER}:${process.env.DB_PASS}@myhost.net?retryWrites=true&w=majority&db=dbname`, { useNewUrlParser: true, dbName: 'dbname' })
    

    process.env.MONGO_CONNECTION_STRING

    Update:

    To overcome the env set command problem in different platforms, you can install cross-env package.

    npm install -D cross-env
    

    And update the scripts:

    "scripts": {
      "start:local": "cross-env NODE_ENV=local npm run start"
      "start:dev": "cross-env NODE_ENV=dev npm run start"
    }