Skip to content

Schemas

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

NestJSConfigManager is essentially a schema-first configuration module. This means that in most use-cases, the configuration process revolves around a schema. A schema is a set of rules that govern:

  • Which environment variables are required
  • For required environment variables, a set of Joi schema rules for validating user-supplied values
  • For optional environment variables, a default value

As described in the Quick Start, you define your schema in a sub-class derived from the ConfigManager class. In that derived class, you implement a required method called provideConfigSpec(). This method takes an optional parameter, environment, containing the value of the current environment, and returns a schema.

A schema is a simple JSON object made up of one key per environment variable that you wish to validate, with each key having a value made up of a simple object with two or three keys. In other words, an entry for the required environment variable DB_HOST would look like:

DB_HOST: {
  validate: Joi.string(),
  required: true,
}

Where validate must be a valid joi schema, and required is a boolean.

If required is false (the default, so you may omit it), you must provide a default value using the default key. In other words, all fields in the schema will be ensured of resolving to a valid value -- either provided by the environment, or provided as a default. For example, specify an optional field like this:

DB_PORT: {
  validate: Joi.number()
    .min(5000)
    .max(65535),
  required: false,
  default: 5432,
}

A complete schema, and the surrounding provideConfigSpec() method, might look like the following. Here we omit required: false on fields that are optional and have a default value. This style is recommended as it reads a little bit more naturally.

  provideConfigSpec() {
    return {
      DB_HOST: {
        validate: Joi.string(),
        required: true,
      },
      DB_USER: {
        validate: Joi.string(),
        required: true,
      },
      DB_PORT: {
        validate: Joi.number()
          .min(5000)
          .max(65535),
        default: 5432,
      },
      FIRST_NAME: {
        validate: Joi.string(),
        required: true,
      }
      PORT: {
        validate: Joi.number()
          .min(3000)
          .max(500),
        default: 3000,
      },
    };
  }

Using the environment parameter in provideConfigSpec()

Your provideConfigSpec() method is called with an environment parameter of type string which is equal to the value of the current environment. In other words, if you're running in development, provideConfigSpec() receives a parameter environment with the value 'development'. This is available in case you want to conditionally enforce different schema validations for different environments.

For example, the following code will ensure that your production environment will use a minimum value of 12 for SALT_ROUNDS:

  provideConfigSpec(enviroment) {
    const MIN_SALT_ROUNDS = environment === 'production' ? 12 : 8;
    return {
      SALT_ROUNDS: {
        validate: Joi.number().min(MIN_SALT_ROUNDS),
        default: MIN_SALT_ROUNDS,
      }
  }

How schemas and module settings are applied

In the How it works section we discussed how basic environment cascades work. The NestJSConfigManager builds on this using schemas to:

  1. Add extra variables from the .env file (if they're allowed)
  2. Apply default values for env vars that are missing
  3. Validate the results

The following diagram shows the entire process. The light blue box (bottom center) shows the series of steps performed by the NestJSConfigManager.

Clone this wiki locally