Skip to content

pedrosodre/nestjs-config-extended

Repository files navigation

Nest Config Extended

Extended Configuration Module for Nest to load environment variables package.

Module Version SonarCloud Alert Status SonarCloud Security Rating SonarCloud Coverage SonarCloud Bugs License Issues GitHub Last Commit

⚠️ Attention: For NestJS v7, this library will maintain 0.x version in maintenance mode only. The 1.x version supports NestJS v8 or later.

Description

Extended Configuration Module for Nest based on the Nest's Configuration Module to load environment variables.

Installation

To begin using it, we first install the module itself.

$ npm i --save nestjs-config-extended

Getting started

Once the module is installed, we can import the ExtendedConfigModule. Typically, we'll import it into the root application module. During the module initialization step, environment variable key/value pairs will be parsed and resolved.

import { Module } from '@nestjs/common';
import { ExtendedConfigModule } from 'nestjs-config-extended';

@Module({
	imports: [ExtendedConfigModule],
})
export class AppModule {}

By default, ExtendedConfigModule will load variables in memory and should be empty since we didn't selected any strategy to load environment variables. If the key/value pairs we want already is on node's process.env, we can just disable cache and work with ExtendedConfigService, by using forRoot() method.

import { Module } from '@nestjs/common';
import { ExtendedConfigModule } from 'nestjs-config-extended';

@Module({
	imports: [
		ExtendedConfigModule.forRoot({
			cache: false,
		}),
	],
})
export class AppModule {}

If needed, you can also initialize ExtendedConfigModule using .forRootAsync() method, to use Nest's dependency injection to provide variables or classes to module's configuration.

Module configuration

To customize module's configuration, you can setup few options by importing it using one of .forRoot() or .forRootAsync() method.

Option Default value Required Type Description
strategies [] false ConfigLoaderStrategy[] Array with all strategies used to load configuration variables.
cache true false boolean If false, values will be stored directly in process.env object.
If true, values will be stored only in the memory.
debug false false boolean If true, module will log some internal process information.
isGlobal false false boolean If true, registers ExtendedConfigModule as a global module.
preload false false boolean If true, variables load will be done by the module and injected on service. This option is required if you need to inject the service on a custom provider and retrieve a variable before application is totally ready.

Strategies

To keep everything as flexible as possible, ExtendedConfigModule works with an array of strategies, that are specialized objects in load environment variables. Each strategy has its own options, as described below:

| Option | Default value | Required | Type | Description | | ------------------ | ------------- | -------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | | loader | - | true | LoaderClass | LoaderMethod | Class or function responsible for loading environment variables for this strategy. Accepts a custom function or class with load() method. | | identifier | - | false | string | Symbol | Identify a strategy to allow module to manipulate it directly on helper functions. | | disable | false | false | boolean | If true, this strategy will not used. This flag is useful to perform conditional strategy disabling. | | options | - | false | Record<string, any> | Set options to loader class or function. | | reloadable | false | false | boolean | If false, this strategy will not be called again when service or scheduler requests a reload. | | schedule | - | false | string | Schedules the strategy reload (if reloadable) using cron syntax. This feature may not work correctly with serverless functions. | | scheduleTimezone | - | false | Timezone | Set scheduler timezone. | | registerAs | - | false | string | If set, all configuration will be set under the key passed on this variable. | | transformer | - | false | TransformerClass | TransformerMethod | If you wish to transform the loaded configuration variables, you can pass a function to handle it. Accepts a function or a class with transform() method. | | validator | - | false | ValidatorClass | ValidatorMethod | If you wish to transform the loaded configuration variables, you can pass a function to handle it. Accepts a function or a class with validate() method. |

Pre-made loaders

Based on key use cases, ExtendedConfigModule has two pre-made loaders. To use them you simply need to import and refer it on strategy's loader option.

  • processEnvLoader: loads variables from node's process.env.
  • dotEnvLoader: loads variables from .env files, based on loader options. You can specify file(s) path and encoding, and enable expandVariables.

Using the ExtendedConfigService

To access the loaded configuration values from our ExtendedConfigService, we first need to inject ExtendedConfigService. As with any provider, we need to import its containing module - the ExtendedConfigModule - into the module that will use it (unless you set the isGlobal property in the options to true). Then we can inject it using standard constructor injection:

constructor(private extendedConfigService: ExtendedConfigModule) {}

Once it's injected, you already can use the following service methods to work with environment variables.

// force load process if didn't started yet
await this.extendedConfigService.load();

// force load process if didn't started yet or wait an in progress load to finish
await this.extendedConfigService.load(true);

// get an environment variable
const dbUser = this.extendedConfigService.get<string>('DATABASE_USER');

// get a proxy of an object from environment variable
const appConfig = this.extendedConfigService.getProxyOf<
	Record<string, unknown>
>('APP_CONFIG');

// verify if an environment variable exists
const hasPassword = this.extendedConfigService.has('DATABASE_USER');

// reload environment variables on strategies that allows reload
await this.extendedConfigService.reload();

// reload environment variables for a specific strategy that allows reload
await this.extendedConfigService.reload('STRATEGY_IDENTIFIER');

⚠️ Important: getProxyOf() method only returns a proxy when returned value is an object, in any other cases, it will return the value directly. If you need a non-object value from the proxy, try encapsulate it with a transformer.

Full example

The examples below uses all availables options to help you to understand the module, but some of them are conflicting.

Using .forRoot()

import { Module } from '@nestjs/common';
import { ExtendedConfigModule, dotEnvLoader } from 'nestjs-config-extended';

@Module({
	imports: [
		ExtendedConfigModule.forRoot({
			cache: true,
			debug: false,
			isGlobal: true,
			preload: true,
			strategies: [
				{
					identifier: 'DOT_ENV_STRATEGY',
					loader: dotEnvLoader,
					disable: false,
					options: {
						path: '.env',
						encoding: 'UTF-8',
						expandVariables: true,
					},
					reloadable: false,
					schedule: '* * * * *', // Every minute, but will not schedule since strategy is not reloadable
					scheduleTimezone: 'America/Sao_Paulo',
					registerAs: 'anyKey',
					transformer: (variables: Record<string, any>) => {
						variables.number = Number(variables.number);
						return variables;
					},
					validator: (variables: Record<string, any>) => {
						if (variables.number > 0) {
							return true;
						}

						return false;
					},
				},
			],
		}),
	],
})
export class AppModule {}

Using .forRootAsync()

import { Module } from '@nestjs/common';
import { ExtendedConfigModule, dotEnvLoader } from 'nestjs-config-extended';

@Module({
	imports: [
		ExtendedConfigModule.forRootAsync({
			isGlobal: true,
			imports: [SampleStrategyModule],
			inject: [SampleStrategyService],
			useFactory: async (loaderClass: SampleStrategyService) => {
				return {
					cache: true,
					debug: false,
					strategies: [
						{
							identifier: 'INJECTED_CLASS_STRATEGY',
							loader: loaderClass,
							disable: false,
							options: {},
							reloadable: true,
							schedule: '* * * * *', // Every minute
							scheduleTimezone: 'America/Sao_Paulo',
							registerAs: 'anyKey',
							transformer: (variables: Record<string, any>) => {
								variables.number = Number(variables.number);
								return variables;
							},
							validator: (variables: Record<string, any>) => {
								if (variables.number > 0) {
									return true;
								}

								return false;
							},
						},
					],
				};
			},
		}),
	],
})
export class AppModule {}

Stay in touch

License

This module is MIT licensed.

Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please read more here.