What Are Node Environment Variables?
Node environment variables are a crucial part of Node.js applications. They are external variables that specify the environment in which the Node.js application runs. These variables, often stored in key-value pairs, can control and influence the behavior of our software in different environments.
These environment variables can hold various types of data, such as application configurations, file paths, and API keys. By storing such data in the environment variables, we can alter the behavior of our application without modifying the codebase. Environment variables also help us manage different configurations for a Node.js application in different environments, such as development, testing, and production.
Two common ways to manage environment variables in Node.js are by getting and setting values in the process.env
object, and using the dotenv
library. We explain both methods in more detail below.
In this article:
Common Use Cases for Node Environment Variables
Configuring Different Application Environments
One of the most common use cases for Node environment variables is configuring different application environments. In modern software development, an application often runs in various environments, such as development, testing, and production. Each of these environments may require different configurations. For instance, a development environment may use a different database connection string than a production environment.
In such cases, Node environment variables come in handy. We can store these configurations in the environment variables, and our application will automatically pick the correct configuration based on the current environment. This approach not only makes our application more flexible but also simplifies the process of deploying our application to different environments.
Dynamically Setting Port Numbers, Service URLs, and Feature Flags
Node environment variables are also useful for dynamically setting port numbers, service URLs, and feature flags. For instance, when deploying our application to a cloud service, we may not know the exact port number that our application will use. In such cases, we can use an environment variable to specify the port number.
Similarly, we may want to use different service URLs or feature flags in different environments. Again, we can use environment variables to handle these scenarios. By doing so, we can make our application more adaptable to different environments and configurations.
Storing Sensitive Data
Another critical use case for Node environment variables is storing sensitive data securely. In most applications there is a need to handle sensitive data, such as database passwords, API keys, and OAuth tokens. Storing such data in the codebase is a bad practice, because code is often committed to source control, where it can easily be compromised by attackers.
Node environment variables offer a slightly more secure way to store sensitive data. We can store this data in the environment variables, and our application can access it when needed. This avoids keeping sensitive data in the codebase, and means that only if an attacker has access to the Node.js runtime environment, they can compromise the data.
However, because environment variables are stored in plaintext, and attackers could conceivably gain access to our environment, storing sensitive information in environment variables is also insecure. Sensitive data should preferably be stored in secrets or via configuration management tools, and their contents should be encrypted.
Tips From Expert
In my experience, here are tips that can help you better use environment variables in Node.js:
-
Validate environment variables at startup
Use libraries likejoi
orenvalid
to validate and sanitize environment variables when your Node.js app starts. This ensures that required variables are defined, have valid values, and prevent runtime errors due to misconfigurations. -
Leverage
.env.example
for sharing variable structure
Create a.env.example
file that lists the required environment variable keys (without sensitive data) for your project. This provides a template for other developers or team members to configure their local environment while keeping sensitive data secure. -
Use different
.env
files for each environment
For better environment management, use different.env
files like.env.development
,.env.staging
, and.env.production
. Dynamically load the appropriate file based on theNODE_ENV
variable to prevent accidental exposure of sensitive production variables. -
Secure environment variables in production
Avoid relying on.env
files in production; use cloud-specific tools like AWS Secrets Manager, Google Secret Manager, or Vault to securely manage production secrets. This limits direct access to sensitive environment variables and improves security. -
Never store large objects or arrays in environment variables
Avoid storing complex data structures (like JSON objects or arrays) in environment variables. Use environment variables only for small pieces of configuration like strings, numbers, and URLs. Store larger configurations in external files or services.
How to Get and Set Environment Variables in Node.js
Getting and setting Node environment variables in Node.js is straightforward. Node.js provides a global object, process.env
, that holds all the environment variables.
To get an environment variable, we simply access the corresponding property of the process.env
object. For instance, if we have an environment variable named DB_PASSWORD
, we can get its value as follows:
const port = process.env.PORT;
On the other hand, to set an environment variable, we can assign a value to the corresponding property of the process.env
object. For example, to set the DB_PASSWORD
environment variable, we can do as follows:
process.env.PORT = '8080';
Remember, the changes we make to the process.env
object only affect the current process. If we want to set an environment variable permanently, we need to do so in our operating system or the hosting platform.
dotenv Library: Managing Environment Variables in Node.js
What Is the dotenv library?
While Node.js provides a simple way to get and set environment variables, managing these variables can be cumbersome, especially when we have a lot of them. This is where the dotenv
library comes in.
dotenv is a zero-dependency module that loads environment variables from a .env
file into process.env
. In other words, it allows us to store our environment variables in a file, making it easier to manage them.
Loading Environment Variables from a .env File
To load environment variables from a .env file, we first need to install the dotenv library. We suggest doing this with nvm (Node Version Manager), because the latest version of dotenv is not currently available via npm.
npm install dotenv
Once installed, we can load the environment variables as follows:
require('dotenv').config();
This line of code will load the environment variables from the .env
file into process.env
.
Configuring and Customizing dotenv
Dotenv also provides various options to customize its behavior. For instance, we can specify a path to the .env
file if it’s not in the root directory of our project:
require('dotenv').config({ path: '/custom/path/to/.env' });
We can also specify a default value for an environment variable that is not set:
require('dotenv').config({ defaults: { PORT: 3000' } });
The output should look like this:
Best Practices for Setting and Using Environment Variables in Node.js
Here are a few best practices that will help you make better use of Node.js environment variables.
1. Keep .env Files Out of Version Control
One of the first things to keep in mind when working with Node environment variables is to keep your .env files out of version control. These files usually contain sensitive information, like API keys, database passwords, and other secrets that should never be exposed publicly.
As a developer, you should never commit these files to your version control system. If you do, you risk exposing this sensitive information to anyone who has access to your repository. This exposure could lead to security breaches and unauthorized access to your systems.
To prevent this, always add .env files to your .gitignore file. This ensures they are not tracked by Git, your version control system, and therefore won’t be committed to your repository.
2. Avoid Hardcoding Secrets
As we’ve already touched on, one of the main uses of Node environment variables is to store secrets, such as API keys and database passwords. It’s therefore critical to avoid hardcoding these secrets into your application code.
Hardcoding secrets is not only a security risk, but it also makes your application less flexible. If you need to change a secret, you’ll have to modify your code, which could potentially introduce bugs.
As mentioned earlier, while it is common practice to store sensitive data in environment variables, it is more secure to store them in secrets or via configuration management tools, which can ensure they are only accessible to authorized parties.
3. Handle Absent Variables Gracefully
Handling absent variables gracefully means that your application should not crash or behave unpredictably if an environment variable is missing.
Instead, your application should have a default behavior in place for when a variable is not defined. This default behavior could be to use a fallback value, or to log a warning message and continue running.
If a missing environment variable is critical to your application, you should have a strategy in place to handle this. This might involve halting the application with a clear error message, notifying you or your team via email, or some other form of alert.
4. Specify Required Variables
In addition to handling absent variables gracefully, it’s also a good idea to specify which environment variables are required for your application to run. This can help you catch issues early on, before they cause problems in your application.
You can do this by checking if the required variables are defined at the start of your application. If a required variable is missing, you can stop the application and log an error message. This gives you a clear indication of what’s wrong, and allows you to fix the issue before it causes further problems.
5. Secure Production Variables
Last, but certainly not least, it’s vital to secure your production environment variables. These are the variables that your application uses when it’s running in the production environment, and they often contain highly sensitive information.
You should always encrypt your production environment variables to ensure they can’t be read if someone were to gain unauthorized access to your system. In addition, you should restrict access to these variables as much as possible, only allowing trusted individuals or systems to read them.
You can use various tools to help secure your production environment variables, including secret management tools or configuration management solutions. These tools can securely store your secrets, and provide them to your application when needed.
Managing Node.js Environment Variables with Configu
Configu is a configuration management platform comprised of two main components, the stand-alone Orchestrator, which is open source, and the Cloud, which is a SaaS solution:
Configu Orchestrator
As applications become more dynamic and distributed in microservices architectures, configurations are getting more fragmented. They are saved as raw text that is spread across multiple stores, databases, files, git repositories, and third-party tools (a typical company will have five to ten different stores).
The Configu Orchestrator, which is open-source software, is a powerful standalone tool designed to address this challenge by providing confConfigu is a configuration management platform comprised of two main components, the stand-alone Orchestrator, which is open source, and the Cloud, which is a SaaS solution:
Configu Cloud
Configu Cloud is the most innovative store purpose-built for configurations, including environment variables, secrets, and feature flags. It is built based on the Configu configuration-as-code (CaC) approach and can model configurations and wrap them with unique layers, providing collaboration capabilities, visibility into configuration workflows, and security and compliance standardization.
Unlike legacy tools, which treat configurations as unstructured data or key-value pairs, Configu is leading the way with a Configuration-as-Code approach. By modeling configurations, they are treated as first-class citizens in the developers’ code. This makes our solution more robust and reliable and also enables Configu to provide more capabilities, such as visualization, a testing framework, and security abilities.