If you are just starting to learn Node.js, then, you will probably see something like this:
app.listen(process.env.PORT)
. Why drive sixteen characters into the code editor when the same effect can be achieved simply by specifying the port number, for example, 3000? We propose to find out.

What is process.env?
The
process.env
global variable is available to the application during its execution due to the internal Node mechanisms. It represents the state of the system environment at the time of launching the application. For example, if the
PATH
variable is set in the system, it can be accessed from the application using the
process.env.PATH
construct. It can be used, for example, if you need to know the place where you can find executable files that you need to access from the code.
About the importance of the environment in which the application runs
As long as the application is not deployed, be it the code that implements the simplest site, or the complex API used in heavy computations, it is completely useless. These are just lines of text stored in files.
')
Being engaged in the creation of programs, the developer never knows exactly where they will work. For example, if the development process requires a database, we launch its instance locally and communicate with it using the connection string, which looks like this:
127.0.0.1:3306
. However, when we deploy a working instance of an application, it may be necessary, for example, to connect to a DBMS located on a remote server, say, accessible at
54.32.1.0:3306
.
If we assume that we do not use environment variables, there are two options.
The first is to ensure the availability of the database on the same machine on which the application is running, which will allow you to connect to it at
127.0.0.1:3306
. This approach means a strong attachment of the application to the infrastructure, its potentially low availability and the inability to scale it, since only one instance of the application can be deployed, depending on a single instance of the DBMS.
The second option involves modifying the code so that during its execution, through a conditional operator with several
else
branches, you can select the appropriate database connection string:
let connectionString; if (runningLocally()) { connectionString = 'dev_user:dev_password@127.0.0.1:3306/schema'; } else if (...) { ... } else if (inProduction()) { connectionString = 'prd_user:prd_password@54.32.1.0:3306/schema'; } const connection = new Connection(connectionString);
Such constructions increase the number of ways to run the program, which complicates testing, and there is no reason to talk about the beauty of the code.
If to specify the connection string to the database, environment variables are used, our task can be solved as follows:
const connection = new Connection(process.env.DB_CONNECTION_STRING);
With this approach, you can both connect to a local instance of the DBMS during development and organize a connection to something like a secure remote database cluster that supports load balancing and knows how to scale independently of the application. This makes it possible, for example, to have multiple instances of an application that are independent of a particular DBMS instance.
In general, it is recommended to always consider the dependencies of the application on some external services as
attached resources and to configure the connection to them using environment variables.
How to use environment variables
Actions that are performed in order to prepare environment variables for an application are called provisioning or preparation for work. When preparing a server, you can distinguish two levels at which you can work with environment variables: the infrastructure level and the application level. You can prepare the environment, either using specialized tools, or - some logic implemented at the application level.
Among the tools that work at the application level, we can mention the
dotenv
package, which will allow you to load environment variables from an
.env
file. You can install this tool like this:
npm install dotenv
The environment variables are loaded using the following simple command:
require('dotenv').config();
This approach is convenient in the development process, but is not recommended in production, therefore, in particular, the
.env
file
.env
best added to
.gitignore
.
At the infrastructure level, you can use tools for managing the deployment of applications like PM2, Docker Compose and Kubernetes to configure the environment.
PM2 uses the
ecosystem.yaml
file, in which you can set environment variables using the
env
property:
apps: - script: ./app.js name: 'my_application' env: NODE_ENV: development env_production: NODE_ENV: production ...
Docker Compose, in a similar way, allows you to set the
environment
property in the service manifest file:
version: "3" services: my_application: image: node:8.9.4-alpine environment: NODE_ENV: production ... ...
Kubernetes has a similar
env
property in the manifest template, which also allows you to set environment variables:
kind: Deployment apiVersion: extensions/v1beta1 metadata: name: my_application spec: ... template: spec: env: - name: NODE_ENV value: production ...
Environment Variable Usage Scenarios
Application Settings
Application settings do not affect exactly what actions this application performs, do not affect its logic. For example, an application knows that it needs to listen on a port in order for it to be accessed from outside, but it does not need to know what kind of port it will be. Such data are quite suitable for putting them into environment variables. Therefore, their installation and preparation of the network infrastructure can be trusted with application deployment tools.
▍ Interaction with external services
Environment variables are often used to specify how an application should connect to the services on which it depends. This allows you to make the code cleaner and improve the testability of the application. In particular, this approach allows the testing environment to transfer to the application certain conditional data that, for example, imitate emergency situations, which allows you to check the application for failures in similar situations. Here we are dealing with a similar situation: the application needs some kind of service, but it is not known in advance where exactly it is located. Setting environment variables for such cases can be trusted with deployment managers.
▍ Development Tools
During local development, it is usually useful to have some kind of software that allows you to quickly get information from the running application or isolate errors. An example of such tools is an interactive reload of a web page after making changes to the application code relating to it. Such behavior can be implemented using conditional constructions, decisions in which are made either on the basis of standard environment variables, such as
process.env.NODE_ENV
, or on the basis of special variables that the developer himself creates, like
process.env.HOT_RELOADING_ENABLED
.
Anti-patterns
Here are some common options for misusing environment variables.
- Excessive use of
NODE_ENV
. In many tutorials you can find recommendations on the use of process.env.NODE_ENV
, but special details about this there may not be found. As a result, there is an unjustified use of NODE_ENV
in conditional statements, contrary to the designation of environment variables.
- Storage of time-dependent information. If an application requires an SSL certificate or a periodically changing password to interact with another application deployed on the same server, it will be unwise to set this data as environment variables. Information about the environment received by the application, represent the state of the environment at the time of its launch and remain unchanged during its operation.
- Setting the time zone. Leon Bambrik said in 2010: “There are 2 complex tasks in computer science: invalidation of the cache, naming of entities, and bias errors by one.” I would add one more here: work with time zones. When an application is deployed in high-availability environments, its instances can be run in different time zones. One copy can work in a data center located in San Francisco, another - in Singapore. And users connect to all of this from London. It is recommended, in server logic, to use UTC, and care about the time zone should be left to the client part of the application.
Results
Proper use of data from
process.env
leads to the development of applications that are easier and more convenient to test, deploy and scale. Environment variables are one of those little things, often almost imperceptible, correct work with which allows you to make the code better, and the wrong one can lead to troubles that tend to manifest themselves at the most unexpected moment. We hope our story about environment variables will help you improve the quality of your programs.
Dear readers! Do you use
process.env
in your projects on Node.js?