Skip to content

EnvVars

Type : class

The EnvVars class is a versatile utility designed for type-safe access to environment variables. It simplifies handling environment variables by offering features such as type parsing, retrieving values tailored to specific environments, reading from various sources, and marking variables as dynamic. Additionally, it ensures robust error handling, preventing your application from proceeding with unexpected behavior when issues arise.

Imagine the following scenario:

let PORT = +(process.env.PORT || 3000);
let HOST = process.env.HOST || 'localhost';
if (process.env.NODE_ENV === 'production') {
PORT = +process.env.PRODUCTION_PORT || throw new Error('Missing production port');
HOST = process.env.PRODUCTION_HOST || throw new Error('Missing production host');
}

This code snippet can become cumbersome to write, maintain, and debug, especially when you have multiple environments and the same variable is used in different places throughout your app. The EnvVars class makes this code much easier to read and maintain, while also providing additional features and robust error handling.

Let’s take a look at how it works:

  1. Imagine your process.env object looks like this:

    {
    PORT: 3000,
    PRODUCTION_PORT: 5000,
    }
  2. Create an envVars.ts file:

    export const envVars = new EnvVars({
    mapObj: {
    port: {
    parseAs: 'number',
    whenNodeEnvIs: {
    production: 'PRODUCTION_PORT',
    anyEnv: 'PORT',
    }
    },
    }
    });
  3. EnvVars takes care of everything by selecting the appropriate value for the current environment, converting it to the correct type, marking it as dynamic if specified, and handling any errors.
    Then you can use the previous envVars.ts file in your code as follows:

    import { envVars } from './envVars';
    console.log(envVars.port); // process.env.NODE_ENV === 'production' ? 5000 : 3000
  4. if the currentEnv is production the previous example will log the number 5000 else it will log the number 3000

Full Example

.env
SECRET_VALUES=1,2,3,4
envVars.ts
import { EnvVars } from '@mustib/utils/node';
export const fromObject = {
PORT: '3000',
}
export const envVars = new EnvVars({
useDynamicValues: true,
enumerable: true,
sources: {
fromFile: 'path to .env file',
fromObject,
fromDynamicFunction: () => ({
HOST: 'localhost',
})
},
mapObj: {
port: {
parseAs: 'number',
whenNodeEnvIs: {
anyEnv: 'PORT',
}},
host: {
whenNodeEnvIs: {
anyEnv: 'HOST',
}},
secretValues: {
parseAs(data) {
return data.varValueForCurrentEnv.split(',')
},
whenNodeEnvIs: {
anyEnv: 'SECRET_VALUES',
}
}
}
})
app.ts
import { envVars, fromObject } from './envVars';
console.log(envVars) // { port: 3000, host: 'localhost', secretValues: [ '1', '2', '3', '4' ] }
fromObject.PORT = '5000'
console.log(envVars) // { port: 5000, host: 'localhost', secretValues: [ '1', '2', '3', '4' ] }
console.log(Object.keys(envVars)) // [ 'port', 'host', 'secretValues' ]

Constructor()

type EnvVars = new (options: ConstructorParams<EnvVarsMapObj>): EnvVars
  • parameters an object with the following properties:
    • useDynamicValues:

      • A boolean indicates whether the generated env object should be dynamic or not.
      • Defaults to false.
    • sources: Used to define the source of environment variables, which can be one of the following:

      • A string representing the path to a .env file
      • A single EnvVarsSourcesObj object, or an array of such objects.
    • mapObj: EnvVarsMapObj

    • currentEnv:

      • a string representing the current env.
      • defaults to process.env.NODE_ENV.
    • enumerable:

      • a boolean indicates whether the generated env object should be enumerable or not.
      • defaults to false.

EnvVarsMapObj

type EnvVarsMapObj = {
[varName: string]: {
parseAs?: ParseAsString | ParseAsFunction
whenNodeEnvIs: {
[envName: string | 'anyEnv']: string
}
useDynamicValue?: boolean
}
}

An object with variable names as keys and their configuration as object with the following properties:

  • parseAs: used to convert the value of the env-var from string to the specified type, possible values are:

    1. A string with the value of "string", "number", "bool", "date" where each value corresponds to a predefined parseAsFunction.
    2. A user-defined function whose return value determines the value and type of the environment variable.
  • whenNodeEnvIs: an object defining the environment variables that should be used for each environment.

  • useDynamicValue: a boolean indicates if the value is dynamic and will be parsed again every time it is needed

EnvVarsSourcesObj

type EnvVarsSourcesObj = {
fromFile: string;
fromObject: Record<string, string>;
fromDynamicFunction(): Record<string, string>;
};

An object that represents a source of environment variables with the following properties:

  • fromFile: A string representing the path to a .env file.
  • fromObject: An object with environment variables.
  • fromDynamicFunction: A function that returns an object with environment variables.

parseAsFunction

type ParseAsFunction = (data: {
combinedEnvVars: Record<string, string>[];
varValueForCurrentEnv: string;
currentEnv: string;
assignedSource: Record<string, string>;
varNameForCurrentEnv: string;
}) => any

A user-defined function whose return value determines the value and type of the environment variable.

It will be called with a data object with the following properties:

  • combinedEnvVars: an array of objects, each representing a source defined in the EnvVars constructor’s sources.

  • varValueForCurrentEnv: the value of the varNameForCurrentEnv in assignedSource object.

  • currentEnv: the current environment (the keys of the whenNodeEnvIs object).

  • assignedSource: the first object from combinedEnvVars that has the varNameForCurrentEnv

  • varNameForCurrentEnv: the name of the environment variable for the current environment (the value of the currentEnv from the whenNodeEnvIs object).
    For example:
    if whenNodeEnvIs has this value:

    const whenNodeEnvIs = {
    production: 'Prod_VAR',
    anyEnv: 'ANY_VAR',
    };

    then the varNameForCurrentEnv will be Prod_VAR for production and ANY_VAR for anyEnv

whenNodeEnvIs

type WhenNodeEnvIs = Record<string | 'anyEnv', string>

An object where the keys are possible environment names and the values are any valid key from combined sources object passed to the EnvVars constructor.

For example, if the environment is production, the value of the key production will be used. If the environment is development, the value of the key development will be used, and so on. If sources has PORT and HOST as variables, then possible values for the whenNodeEnvIs object are PORT and HOST.

The special key anyEnv can be used to specify a fallback value for any environment. This is useful when you want to provide a default value for an environment variable that is not defined in the current environment.