Skip to content

Module configuration options

John Biundo edited this page Aug 24, 2019 · 15 revisions

Table of Contents

Module setup - options overview

Normal operation is to set up the NestjsConfigManager using the register() method. This step is sometimes referred to as "configure" with other Nest modules, but since "configure" is part of the name of this module, we'll use the term set up. Rest assured, this is the exact same way you normally configure an add-on Nest module. Note also that add-on modules vary between using the method name register() and forRoot() for this configuration method, but they are otherwise equivalent in function.

You saw an example of this setup step in the Quick Start with code like:

@Module({
  imports: [
    ConfigManagerModule.register({
      useEnv: {
        folder: 'config',
      }
    }),
  ],
  providers: [ConfigService],
  exports: [ConfigService],
})

The NestJSConfigManager is a fully asynchronous and dynamic module, which means that you can do this registration synchronously (using the register() method shown above) or asynchronously (registerAsync() as described later on this page).

To use register(), pass it an options object of type ConfigOptions. ConfigOptions is defined as follows:

interface ConfigOptions {
  envKey?: string;
  useFile?: string;
  useEnv?: boolean | { folder?: string; };
  useFunction?: (rootFolder: string, environment: string) => string;
  defaultEnvironment?: string;
  allowExtras?: boolean;
  allowMissingEnvFile?: boolean;
}

envKey option

The envKey option takes a string naming the environment variable that is used to determine the current environment.

The term current environment corresponds to the conventional use of the environment variable NODE_ENV to designate whether a particular runtime environment is something like 'production' or 'development'. As mentioned, this is just a convention, and you can easily extend the set of possible values to model other environments like 'staging', etc.

NestJSConfigManager uses the current environment to help determine the location of the .env file, as you'll see below.

The default value for envKey is NODE_ENV, following the above convention. This means NestJSConfigManager will check the value of the NODE_ENV environment variable to determine the current environment.

However, you may choose any environment variable to model your current environment. For example, you may choose to use the environment variable MY_ENVIRON, in which case you would:

  • First, ensure that this variable is set to the proper value (such as 'development', 'test' or 'production').
  • Register this with the ConfigManagerModule using the useEnv option.

Note that envKey (and the current environment) is used by NestJSConfigManager when the useEnv or useFunction methods of determining the location of the .env file is employed, but is ignored for the useFile method.

Methods for determining location of the env file

There are three mutually exclusive options for determining the location of the .env file. Choose one of these. For each, the concept of root folder is important. NestJSConfigManager determines the root folder as either:

  • The project root folder (this applies to running in development mode)
  • The current working directory - if it cannot determine the project root folder, it will use the current working directory (process.cwd()), which is the directory where the node command was invoked.

useFile

With useFile you supply a path and filename relative to the root folder. envKey is ignored.

useEnv

The value of useEnv can either be a boolean (true to enable it, and accept the default folder setting), or an options object specifying a folder. For example:

// no folder specified; folder sub-option will default to using the `config`
// subfolder below the 'root folder'
ConfigManagerModule.register({
  useEnv: true
})

or

ConfigManagerModule.register({
  useEnv: {
    folder: 'myconfigs'
  }
})

With useEnv, NestJSConfigManager uses the environment variable specified in envKey (or NODE_ENV if envKeyis omitted) to build the name of the .env file. It does so by prepending the value of the envKey with the string .env. For example, if the envKey is NODE_ENV, and its current value is 'production', the filename portion of the .env file that it will look for is

production.env

useEnv has a sub-option (folder) that specifies the path, relative to the root path, in which NestJSConfigManager will look for the .env file. If omitted, the folder used will be the root path concatenated with /config. Usually you want to specify a folder when using the useEnv option.

useFunction

The useFunction method takes as its value a function with the following signature

(rootFolder: string, environment: string) => string;

If using this method, you must supply a function that constructs and returns the appropriate full file path (an absolute file path, based on the rootFolder value, including a filename). For example, take a look at the configResolver function below:

import { Module, Global } from '@nestjs/common';
import { ConfigManagerModule } from '@nestjsplus/config';
import { ConfigService } from './config.service';

function configResolver(rootFolder, environment) {
  return `${rootFolder}/config/${environment}.env`;
}

@Global()
@Module({
  imports: [
    ConfigManagerModule.register({
      useFunction: configResolver,
    }),
  ],
  providers: [ConfigService],
  exports: [ConfigService],
})
export class ConfigModule {}

Using this mechanism, NestJSConfigManager will look for different .env files based on runtime information. For example, if running inside a Docker container with the NODE_ENV variable set to production, and the Docker WORKDIR set to /app, NestJSConfigManager with this resolver function will look for the file

/app/config/production.env

On the other hand, if the app is running in development and the project root folder is /home/john/myapp, and NODE_ENV is set to development, it will look for the file

/home/john/myapp/config/development.env

With this mechanism, you can both preserve the relative location of the env file (for both environments, it's in the /config sub-folder which in turn is is within the root folder) and dynamically determine the name of the file (e.g., vary it from development to production). In other words, the function you supply delivers a mapping that supplies the appropriate .env file for each environment.

This, in conjunction with the cascade, should allow you to manage deployment by simply switching out your environment (e.g., possibly using a .env file in development, but external environment variables in production).

Other module configuration options

defaultEnvironment

Imagine you do not want to use .env files in production (some consider it best practice to avoid doing so), but do want to use them in development. So far so good. However, this means that you will need to ensure that an environment variable (typically NODE_ENV) is set in everyone's development environment. While this is certainly common and not too complicated, it can be convenient to bypass this requirement and simply establish a default value for the current environment. Use the defaultEnvironment option to do so. When it is set, if no NODE_ENV (or alternative environment variable you have chosen to indicate the current environment) value is set, the defaultEnvironment will be used. If a value is found for the NODE_ENV (or your alternative) environment variable, that will be used. If you set this option, ensure that you override its behavior in production by setting the value for NODE_ENV (or your alternative).

allowExtras

This optional boolean field determines whether the NestJSConfigManager will allow extra variables (those not defined in the schema) in the .env file. Defaults to false. When true, will take the exit action (see onError below) if the .env file has variables not declared in the schema.

This can be useful during rapid prototyping when you just want to quickly add a new environment variable. Note that, because there is no schema validation for such extra variables, their values will not be validated.

onError

This optional string field determines the exit action: namely, what happens when NestJSConfigManager encounters an error. You want to consider this setting carefully. The default action is exit, which causes the process to exit (process.exit(0)). This is the default because normally, if you have an invalid configuration, the application is in an unknown state. Since typically the rest of your code assumes the application is configured correctly, you probably want to avoid being in this unknown state.

You may also choose one of two other alternatives:

  • throw - instead of exiting, your config service will throw an InvalidConfigurationError error. This can be useful when running unit tests, as it's easier to test for exceptions than process exits. If the configuration service throws due to failed variable validations, the InvalidConfigurationError will have two properties (missingKeys and validationErrors) that you can inspect to determine the nature of the failure.
  • continue - instead of exiting or throwing, the application will continue, ignoring any configuration errors. This mode is not recommended except for testing/prototyping.

allowMissingEnvFile

If false (the default), the configuration service will take the exit action if there is no .env file found.

If true, the configuration service will ignore the fact that a .env file is missing and simply proceed to load using just the external environment.

For example, if your policy is to not use .env files in production, but only use external environment variables, you should set this option to true.

In development, failure to resolve a .env file might be considered an error.

Asynchronous registration

NestJSConfigManager also supports asynchronous registration using the registerAsync() method. As with other modules, you can use any of the following methods:

  • useFactory
  • useClass
  • useExisting