Albert
Albert

Reputation: 2664

How to manage different config environments in nestjs

I'd like to have a few environments, let's say development, production, test. These environments should be independent and use their own set of config parameters, e.g. for DB, SERVER_PORT, USER etc. They should not be in the code base, so I think they should be different .env files. That's to say, I should be able to load different .env files depending on what environment is active. Also, it's not clear where I have to set that env switcher.

Maybe it should be a single .env file that has the NODE_ENV parameter, that param can be set to any of the above-mentioned values, be that development, production or test. And depending on the value of this parameter a necessary set of config parameters gets automatically loaded.

I've read the documentation, it seems a little confusing to me at the moment.

Seems like there should be some config factory.

Upvotes: 34

Views: 34977

Answers (5)

RiverRay
RiverRay

Reputation: 129

another code style~

if you want to deeply use @nestjs/config , try like this

mkdir a dictionary named config, structure

- /config
  - config.default.ts
  - config.dev.ts
  - config.production.ts
  - configuration.ts

set individual config in config.ENV.ts like this

export default {
  // nodemailer config
  mailer: {
    host: 'xxx',
    port: 80,
    auth: {
      user: 'xxx',
      pass: 'xxx',
    },
    secure: false, // or true using 443
  },
  // jwt sign secret
  jwt: {
    secret: process.env.JWT_SECRET || '123456',
  }
}

then dynamic exports these file in configuration.ts

import { merge } from 'lodash';
import DefaultConfig from './config.default';



export default () => {
  let envConfig = {};
  try {
    // eslint-disable-next-line @typescript-eslint/no-var-requires
    envConfig = require(`./config.${process.env.NODE_ENV}`).default;
  } catch (e) {

  }
  
  return merge(DefaultConfig, envConfig);
};

import configuration.ts in app.module.ts


import configuration from './config/Configuration';

@Module({
  imports: [
    ConfigModule.forRoot({
      load: [configuration],
    }),
  ],
})

that's all

Upvotes: 3

cksrc
cksrc

Reputation: 2347

The trick is to define custom filename paths for the envFilePath configuration of Netjs's ConfigModule that is based on the environment variable NODE_ENV. You can then set the value of NODE_ENV in your different scripts in your package.json

In your app.module.ts add

// Grab the system env variable
const ENV = process.env.NODE_ENV;

// Set custom filepath in ConfigModule properties based on NODE_ENV
@Module({
  imports: [
    ConfigModule.forRoot({
    envFilePath: !ENV ? '.env.dev' : `.env.${ENV}`
    })
  ]
})

In your package.json file modify your "scripts" to set NODE_ENV

"scripts": {
  "start:dev": "NODE_ENV=dev nest start --watch",
  "start:prod": "NODE_ENV=prod node dist/main"
}

Upvotes: 1

Kessir
Kessir

Reputation: 941

Assuming you have the following config files in the root of the project: env.development, env.staging, env.test

Here is how I would implement it:

In the app.module.ts file:

import { ConfigModule } from '@nestjs/config';

const ENV = process.env.NODE_ENV;

@Module({
  imports: [
    ConfigModule.forRoot({
      envFilePath: !ENV ? '.env' : `.env.${ENV}`,
    }),
  ],
  controllers: [AppController],
})
export class AppModule {}

Inspired by this solution: https://github.com/nestjsx/nestjs-config#using-different-env-files

Upvotes: 57

Somesh Mohan
Somesh Mohan

Reputation: 51

You can use the config library as mentioned in the official documentation. Otherwise you can use the npm library dotenv.

In either way what really matters is how you organise your .env files. Env files are supposed to contain database credentials, encryption secret and many confidential data, so its not really a good idea to put them in version control. Instead you should store the .env file in the system. Production server will have .env file with production secrets, developer server can have .env file with local secrets. Flag .env to be ignored by git. In this way you won't have to change according to environment, it will automatically take the right configuration based on which server you are deploying.

Upvotes: 4

Moazzam Arif
Moazzam Arif

Reputation: 318

There are two approaches to this use case.

1.create .prod.env, .development.env, .test.env and load required env like this.

ConfigModule.forRoot({envFilePath: '.development.env'});

2.create config from function

export default () => ({
  port: parseInt(process.env.PORT, 10) || 3000,
  database: {
    host: process.env.DATABASE_HOST,
    port: parseInt(process.env.DATABASE_PORT, 10) || 5432
  }
});

and use

@Module({
  imports: [
    ConfigModule.forRoot({
      load: [configuration],
    }),
  ],
})

see more here

Upvotes: 0

Related Questions