How to Use Environment Variables in Node.js
With Node’s environment variables, we can configure our applications outside of our codebase. Environment variables provide information about the environment in which the process is running. We use Node environment variables to handle sensitive data like passwords, which we shouldn’t hard code, or configuration details that might change between runs, like what port a server should listen on. In Node.js these special variables are accessible on the global process.env
object.
In this tutorial, we’ll:
- Learn what Node environment variables are, and when you should use them
- Learn how to create and use Node environment variables
- Learn how to configure your Node application to work with environment variables, including using .env files and the dotenv package
- Show how to read and set environment variables with Node.js
By the end of this tutorial you will be able to explain what Node environment variables are, identify common use cases, and know where to find more information about how to get started using them in your own code.
Goal
Understand what environment variables are and how to use them.
Prerequisites
- None.
Watch
What are environment variables?
Environment variables allow your application to behave differently based on the environment in which it’s running. Separating your application from its configuration is an important part of building 12 factor applications, and a recommended best practice.
There’s a good chance that the code you’re writing will run in a variety of different environments. The production version might run on a cloud services provider like AWS, Azure, or as part of a Netlify serverless function. When you’re working on developing new features you might execute it directly on your laptop, or within a docker container. And while you’re using Linux, one of your teammates might be running macOS.
While running the application on your laptop during development, you might want to point at a copy of the production database for testing purposes rather than the real thing. Or maybe you want to run the application in debugging mode so that you get helpful output while testing.
Maybe you’re connecting to a third party API and it requires a secret access token that you don’t want to share. Or maybe you want to ping a different endpoint when testing the application so you don’t affect production data.
Rather than hard coding values that change per environment or context into your application, it’s better to make these configurable options which can be set by the environment where the code is running.
This is where environment variables come in handy. Generically, environment variables are variables whose value is set outside the process itself, typically through functionality built into the operating system or service in which the code is executed. They allow dynamic data to be communicated between the host environment and the specific process. The process should be able to assume that those variables will exist without having to worry about how they are initialized.
Using environment variables for configuration has one distinct advantage over something like a config.js or config.json file. They’re already part of the system. Every environment will already have a built in way to handle them. And when it comes to automation it allows you to avoid doing awkward things like scripting the creation of a config.json file.
Common examples and use cases
Perhaps the most common example of an environment variable is the $HOME
variable provided by your OS. It points to the home directory of the current user. Any application has access to this variable, and different applications can use it for different purposes, like storing downloaded files in $HOME/Downloads or sourcing the $HOME/.profile of the user when starting a new bash session. The application doesn’t care where the OS has decided to place the directory, as long as it can find it when it needs it.
In Node.js applications a common use case is for usernames, passwords, and API credentials that need to be kept secure and shouldn’t be hard coded into the application’s code — or those that might change depending on the environment. For example, you probably use a different username and password to secure your database in production than you do on your localhost. In order to account for this, rather than hard-coding these values into your application you can instead read their values from the current environment.
Use cases for environment variables
- Execution mode for an application, e.g. ‘development’ vs. ‘production’
- API keys, URLs, and other configuration. This is data that you want to keep secret and not commit to version control. It also might change depending on the context the application is executed in. For example, you might point to a test payment gateway when running the application in a development environment and the active payment gateway for the production environment.
- Which HTTP port a server should listen on
- Passwords, or any other credentials that need to be secure and should NOT appear on the source code itself
- The location of the host environment’s temporary files directory
From https://12factor.net/config:
A litmus test for whether an app has all config correctly factored out of the code is whether the codebase could be made open source at any moment, without compromising any credentials.
Environment configuration vs. application configuration
It’s important to distinguish between environment configuration and application configuration.
Environment configuration is any configuration that could potentially vary per deploy (staging, production, developer environments). It includes things like resource locators, credentials, and per-deploy values like the canonical URL. These values should never exist in the code itself. Environment variables provide a convenient way to deal with these values.
Application configuration refers to things like Express.js route configuration, which authentication middleware to use, or the content of the email welcoming new users. This configuration doesn’t vary between deploys, and is best kept in version control.
Reading environment variables with Node.js
At runtime, Node.js automatically loads environment variables into the global object process.env
to make them available to the application.
Here’s a basic example of reading an environment variable with Node.js:
const name = process.env.NAME;console.log(`Hello, ${name}`);
Run hello.js and set the NAME environment variable for the process:
NAME="Joe" node hello.js# => 'Hello, Joe'
Setting environment variables for Node.js applications
Generally speaking it’s the job of the host environment to define how environment variables are set. See the section about .env files below for an exception to this rule.
A bash shell on your localhost can set them with export
:
#!/bin/bashexport NAME='Joe'export DEBUG=true
node ./hello.js
Cloud hosting tools like Netlify provide a UI for setting environment variables:
Consult your environment’s documentation for more information on how to set custom environment variables.
Using a .env file to set environment variables
Managing more than a couple of environment variables for your application can be cumbersome:
- Where do you find a list of what variables need to be set?
- How do you keep track of the values you want to set them to?
- Typing them at the command line every time you execute your code is error prone and tedious
By far the most common solution to this in the Node.js world is the dotenv library. This allows you to create an .env file in the root directory of your codebase which contains key/value pairs defining environment variables. This file is read by the dotenv library and appended to the process.env
global.
With this solution you only need to configure the .env file once per environment and then run your application like normal.
While the .env file itself should be environment-specific and not in version control, you can create an .env.example file that documents the necessary variables and commit that to your codebase. This provides a useful reference for anyone executing the application and wondering what variables need to be set, and what effect different values will have.
You can read more about using .env files in Setup and Test a .env File.
A word of caution
Remember to never commit sensitive information like passwords or API keys to version control. Use environment variables instead.
We recommend adding .env
to your .gitignore file. As a precaution adding, and committing, this change before you create an .env file for your project can help eliminate any risk of accidentally committing the file.
Recap
In this tutorial we defined environment variables as key/value pairs set by the host environment within which a Node.js process is running — not by the process itself. The application can access these variables via the process.env
global in order to obtain information about the environment itself like the location of a directory, as well as any configuration that could potentially vary per deploy like API keys or resource handles. We covered some common use cases and examples, and ended by starting to look at how to make use of environment variables in our code.
Further your understanding
- Learn more about using environment variables in Setup and Test a .env File (heynode.com)
- Can you get a list of the variables that exist in the environment where you’re currently executing your Node.js code? How do you change their values?
Additional resources
- Node.js
process.env
documentation (nodejs.org) - What are environment variables in Bash? (opensource.com)