If you're currently configuring your applications like this, don't worry, you're not alone! Most developers eventually realize that hard-coding credentials isn't the way to go, and begin looking for a more secure alternative in the form of a secrets manager.
This is exactly we created Doppler—giving developers an easy to use secrets manager for Node.js applications that centralizes secrets storage with an easy to use CLI for injecting secrets as environment variables.
Environment variables are considered the best way to configure applications, with the main benefits being:
Specifically, you could use environment variables to:
Note: If you haven't worked much with environment variables on the commandline, check out our ultimate guide for using environment variables in Linux and Mac.
When your Node.js application starts or a script is run, a new (child) process is created which inherits the environment variables from the parent process. Node parses the environment variables, creating a process.env object where every key and value is a string.
Using an interactive Node terminal, we can inspect the contents of process.env:
Now you know how environment variables in Node.js are populated, let's learn how to work with them.
Accessing an environment variable from process.env is no different to that of a regular object:
The one notable difference with the process.env object, is that every key and value will always be a string. This is because environment variables themselves can only ever be strings.
If a value you're accessing from an environment variable needs to be a non-string type, you must parse or cast it yourself, e.g. casting a PORT environment variable to an integer:
While the syntax for accessing an environment variable is simple, more thought is required when deciding how environment variables are parsed and used, e.g. how to handle the case when a required variable is not supplied.
One option is to use the ok method from the assert module:
If executed without setting the API_KEY environment variable, you'll be greeted with something like the following:
Why use assert.ok? Because we want our application to throw an exception and exit if it's not configured properly.
You might be thinking "that's kinda ugly" which personally I'm ok with, as it should be a rare exception that your app is incorrectly configured.
If you wanted to handle this case with nicer output, you could use something similar to:
Now if executed without setting the API_KEY environment variable, the output would be:
Whichever you choose is personal preference—the main thing being that you're handling the case of a missing required environment variable strictly and correctly.
You can have a default value returned if an environment variable doesn't exist by using the || (OR) operator:
So while the code to provide default values is simple, you should try to avoid defaults in your application code, the reasons of which I'll cover next.
The reason for avoiding defaults for environment variables is simple: A single source of truth should exist for any app config and secret value.
When debugging your application because it is misconfigured (and trust me, it's only a matter of time), the removal of defaults means every config or secret value was supplied by environment variables—that's your source of truth.
Default values in application code can make debugging a misconfigured application more difficult, as the final config values will likely be a combination of hard-coded default values and environment variables.
Make life easier for your future self (and team) by requiring all app config and secret values be set explicitly using environment variables.
Setting or creating a new environment variable in Node.js is the same as setting a key on a standard object, except Node will implicitly convert any non-string value to a string.
It's recommended to always convert a value you wish to set as an environment variable to a string first, as future versions of Node may throw an exception if a non-string value is assigned.
When it comes to changing Node.js environment variables, there are two things to be aware of:
Deleting a Node.js environment variable is the same as deleting a key from a standard object:
Deleting an environment variable only affects the current script or application and doesn't affect the parent process.
As an aside, if you're confused as to why deleting a key from process.env is always true (even once the key has been deleted), you're not alone.
It's because it will only return false if the property is "non-configurable", such as Math.PI or a property created as a result of calling Object.defineProperty() or Object.freeze().
Check out the Mozilla docs for the delete operator if you'd like to know more.
As an application grows in size and complexity, so does the number of environment variables needed for app config and secrets.
While .env files are simple and easy to get started with, they also cause a new set of problems such as:
Doppler provides an access-controlled dashboard for managing environment variables in every environment with an easy-to-use CLI for accessing config and secrets that work for every language, framework, and platform.
The NODE_ENV environment variable originally came the Express web framework and was used to alter internal behavior, such as caching templates and using less verbose logs if NODE_ENV was set to production.
It has since become a popular Node.js convention for conditional logic based on the environment type, for example:
Awesome work! Now you know how to use environment variables in Node.js for application config and secrets.
Although we're a bit biased, we encourage you to try using Doppler for managing your Node.js environment variables, and it's free to get started with our Community plan (unlimited projects, secrets, and users).
To see Doppler in action, check out the Mandalorion GIF sample application.