My Favorite Tool for Managing Project-Specific Environment Variables

With many local projects, environment variables often conflict with one another. I tried several tools before landing on my favorite for managing project-specific values.

How many code-based projects do you have on your machine? I have more than 30 that I've touched within the last month. More than half use environment variables to manage sensitive and environment-specific data.

If it hasn't happened yet, at some point you are going to run into a situation where two environment variables of the same name require different values for different projects. This usually happens with generically-named variables, like GOOGLE_API_KEY or AWS_SECRET_ACCESS_KEY.

Trials and (Minor) Tribulations

I've gone through several iterations on handling project-specific settings.

For awhile I used tools like Figaro (for Ruby on Rails) to enable me to place project- and environment-specific values in a single file (ignored by git). This worked well, but I wasn't 100% happy with it because the tool was specific to Rails, so when I had front-end only apps, I was forced to use a different strategy. Managing environment variables differently from project to project made context switching even difficult.

Then I discovered dotenv which is built for JavaScript (solving most of my front-end problems), but also has a ruby alternative that works similarly. After employing dotenv, I had project-specific environment-variable parity among most of the projects on my machine.

But I still wasn't totally happy (apparently I can be difficult to please) because it didn't just work. I could have a .env file within my project with all my sensitive and environment-specific values, but unless I initialized dotenv, then values wouldn't be available at runtime.

direnv To The Rescue!

I struggled down the dotenv road for for several months before discovering direnv—the tool I should have been looking for from the beginning.

While dotenv hooks into the process you run, direnv hooks into the shell, and thus is available to any process within a given shell session.

Direnv looks for a single file—.envrc—in any directory. When you change into a directory containing a .envrc file, it loads that file's contents into your environment (after you allow it)automatically. This means you don't have to do any extra work, the environment variables are set automatically. As a bonus, direnv knows when you've made changes to your .envrc file and prompts you to re-allow the file before it will load the values into your environment.

direnv supports several operating systems out of the box (although it seems like Windows support is still being developed at the time of writing this article). Once you've installed it, working with it is super simple. Let's go through a quick example:

Use your terminal to change into a project directory:

$ cd path/to/project

Create a .envrc file at the project root and export some environment variable. We'll use MY_VALUE as the test case:


export MY_VALUE="Hello World"

Now, when you type a new command or even just hit Enter in your terminal, you'll see a warning that a change has been made to the .envrc file, but you haven't approved it to pass into the environment just yet.

$ ...
direnv: error .envrc is blocked. Run `direnv allow` to approve its content.

So you simply do what it says and direnv will tell you what it loads into the environment:

$ direnv allow
direnv: loading .envrc
direnv: export +MY_VALUE

Now if you export the environment variables you'll see your new value:

Other env vars ...
MY_VALUE=Hello World

That's all you have to do, and now ENV['MY_VALUE'] is available in your project, assuming you are running the project from a terminal session!

Let's Connect

Keep Reading

When to Use Environment Variables

Environment variables can seem like overkill to new developers, but there are two scenarios in which they are extremely beneficial to efficiency and security.

Jan 14, 2019

Decreased Jekyll Build Times 5x with a Custom Asset Pipeline

My team and I ditched the jekyll-assets gem for a homegrown asset pipeline and decreased build times by a factor of five. This is how we did it.

Jan 10, 2019

Node.js Memory Error on Mac Using M1

How to fix Node.js memory error on Mac OS X using Apple M1 chip.

Feb 08, 2021