Languages
[Edit]
EN

Node.js - read .env file (custom solution)

10 points
Created by:
Gigadude
791

In this short article, we would like to show some custom implementaion that lets to read environment variables from .env file under Node.js.

 

The below implementation provides the following API:

Constants:

ENV_PATH: string;

property that contains default env file name (.env).

Functions:

readVariables(path: string, constants: Record<string, () => string>): Record<string, string>;

function that reads .env file variables and returns them as object.

ArgumentDescription
path

path to .env file (optional)

constants

key -> function map that lets to inject prefefined variables in .env file (optional)

e.g.

Example index.js file:

const {readVariables, ENV_PATH} = require('./env');

const ENV_CONSTANTS = {
    CONSTANT_NAME: () => 'Hi there!'
};

const variables = readVariables('.env', ENV_CONSTANTS);

console.log(variables.VARIABLE_NAME_1);  // Message
console.log(variables.VARIABLE_NAME_2);  // Message: Hi there!
console.log(variables.VARIABLE_NAME_3);  // /home/john: Message: Hi there!

Example .env file:

VARIABLE_NAME_1=Message
VARIABLE_NAME_2=$VARIABLE_NAME_1$: %CONSTANT_NAME%
VARIABLE_NAME_3=*HOME*: $VARIABLE_NAME_2$

Where:

  • $VARIABLE_NAME_1$ and $VARIABLE_NAME_2$ allow access to local variables defined in .env file,
  • %CONSTANT_NAME% allows access to pre-defined constant in application source code,
  • *HOME* allows access to pre-defined variable in process.env object.

Example output:

Message
Message: Hi there!
/home/john: Message: Hi there!
Resultobject that contains read environment variables (key -> value map)

initializeVariables(path: string, constants: Record<string, () => string>): void;

function that reads .env file variables and sets them in process.env object (key -> value map).

ArgumentDescription
pathpath to .env file (optional)
constants

key -> function map that lets to inject prefefined variables in .env file (optional)

Resultnothing

 

Practical example

Project structure:

/opt/my-website/
        ├─ frontend/
        └─ backend/
              ├─ index.js
              ├─ env.js
              └─ .env

 

Example index.js file:

const {initializeVariables, ENV_PATH} = require('./env');

const ENV_CONSTANTS = {
    __dirname: () => __dirname,           // use it in `.env` file as %__dirname%
    __filename: () => __filename          // use it in `.env` file as %__filename%
};

initializeVariables(ENV_PATH, ENV_CONSTANTS);  // ENV_CONSTANTS enables constant values injection (we can use e.g. VARIABLE_NAME=%CONSTANT_NAME%)

console.log(process.env.BACKEND_PATH);
console.log(process.env.FRONTEND_PATH);

Note:

When you use __dirname or __filename in ENV_CONSTANTS be sure what values are returned. It is recommended to create ENV_CONSTANTS object and read .env file in index.js file in the project root directory.

Example output:

/opt/my-website/backend
/opt/my-website/frontend

 

Example .env file:

APPLICATION_PATH=%__dirname%

BACKEND_PATH=$APPLICATION_PATH$/backend
FRONTEND_PATH=$APPLICATION_PATH$/frontend

 

Example env.js file:

const fs = require('fs');


const NEWLINE_EXPRESSION = /\r?\n/g;

// Syntax:
//
//   %NODE_CONSTANT_NAME%    - constant defined in application source code
//   $LOCAL_VARIABLE_NAME$   - variable defined in `.env` file
//   *GLOBAL_VARIABLE_NAME*  - variable defined in `process.env` object
//
const REFERENCE_EXPRESSION = /%%|%([^%*$]+)%|%|\*\*|\*([^%*$]+)\*|\*|\$\$|\$([^%*$]+)\$|\$/g;

const ENV_PATH = exports.ENV_PATH = '.env';


const iterateVariables = exports.iterateVariables = (text, callback) => {
    const lines = text.split(NEWLINE_EXPRESSION);
    for (let i = 0; i < lines.length; ++i) {
        const line = lines[i];
        if (line) {
            const index = line.indexOf('=');
            if (index !== -1) {
                const name = line.substring(0, index);
                if (name) {
                    const value = line.substring(index + 1);
                    callback(name, value, i);
                }
            }
        }
    }
};

const readVariables = exports.readVariables = (path = ENV_PATH, constants = {}) => {
    const text = fs.readFileSync(path, 'utf-8');
    const variables = [];
    const environment = process.env;
    iterateVariables(text, (name, value, index) => {
        const action = (match, group1, group2, group3) => {
            switch (match) {
                case '%': throw new Error(`Incorrect '%' character usage in 'name=${value}' line (line number: ${index + 1}).`);
                case '*': throw new Error(`Incorrect '*' character usage in 'name=${value}' line (line number: ${index + 1}).`);
                case '$': throw new Error(`Incorrect '$' character usage in 'name=${value}' line (line number: ${index + 1}).`);
                case '%%': return '%';
                case '**': return '*';
                case '$$': return '$';
                default:
                    switch (match[0]) {
                        case '%':
                            {
                                const constant = constants[group1];
                                if (constant) {
                                    return constant();
                                }
                                throw new Error(`Unknown '%${group1}%' environment constant.`);
                            }
                        case '*':
                            {
                                const variable = environment[group2];
                                if (variable == null) {  // null or undefined
                                    throw new Error(`Unknown '%${group2}%' environment variable.`);
                                }
                                return variable;
                            }
                        case '$':
                            {
                                const variable = variables[group3];
                                if (variable == null) {  // null or undefined
                                    throw new Error(`Unknown '$${group3}$' environment variable.`);
                                }
                                return variable;
                            }
                        default:
                            throw new Error(`Unknown constant/variable type.`);
                    }
            }
        };
        variables[name] = value.replace(REFERENCE_EXPRESSION, action);
    });
    return variables;
};

const initializeVariables = exports.initializeVariables = (path = ENV_PATH, constants = null) => {
    const variables = readVariables(path, constants);
    const keys = Object.keys(variables);
    for (const key of keys) {
        process.env[key] = variables[key];
    }
};

 

Alternative titles

  1. Node.js - use .env file (custom solution)
  2. Node.js - read environment variables from file (custom solution)
Donate to Dirask
Our content is created by volunteers - like Wikipedia. If you think, the things we do are good, donate us. Thanks!
Join to our subscribers to be up to date with content, news and offers.
Native Advertising
🚀
Get your tech brand or product in front of software developers.
For more information Contact us
Dirask - we help you to
solve coding problems.
Ask question.

❤️💻 🙂

Join