One Environment per Project: Manage Directory-Scoped envs with direnv in POSIX Systems
Tags: linux, bash, unix, direnv
Published: 2021-11-20 14:41:58

---
title: One Environment per Project: Manage Directory-Scoped envs with direnv in POSIX Systems
published: true
description: Manage your environment variables with direnv
tags: linux, bash, unix, direnv
//cover_image: https://direct_url_to_image.jpg
---

## Introduction

One of the more common practices in software projects is to keep certain information separated but accessible from the codebase which uses it. This is usually done with secrets such as passwords or private keys, and also with user or context-specific info pieces. However, management of environment variables can be a pain. The solutions to ease it are many, and there are even built-in ones such as [bash_profile](https://www.baeldung.com/linux/bashrc-vs-bash-profile-vs-profile). 
One solution I've discovered recently and found particularly convenient is [direnv](https://github.com/direnv/direnv), a shell extension which enables definition of environment variables scoped by directory. After installing & hooking the extension to your shell, `direnv` will execute every time you change directories, looking for an `.envrc` file in the same or in a superior directory tree level. It will then load the defined variables to the current environment, and unload them if it ceases to detect the same `.envrc`.
Note that `direnv` will load the first detected `.envrc` file, which means that *the environment will* **not** *inherit values from a* `.envrc` *in a parent directory*.
It is also important to keep in mind that the environment variables *will only be loaded to your shell session once you move to a directory affected by a* `.envrc` *file*. So if you try something like running a script which loads an environment defined in a directory below your current level, the variables wouldn't be accessible.


## Install

Here's the [list of supported systems](https://direnv.net/docs/installation.html), it is very likely your UNIX-based system's main open source package manager has it available. Suppose we are on Debian, we can install `direnv` by running the standard external package install command in the terminal:

```bash
sudo apt-get install direnv
```

## Setup

After installation, we must hook `direnv` to our shell. Supposing we are using bash, we can accomplish this by appending this line to the end of our shell startup config file:
```bash
echo 'eval "$(direnv hook bash)"' >> ~/.bashrc
```

Almost the same for ZShell:

```bash
echo 'eval "$(direnv hook zsh)"' >> ~/.zshrc
```

Direnv also supports FISH, TCSH & Elvish. [Here are the hooking instructions for each supported shell](https://direnv.net/docs/hook.html).

## Using direnv

Now we must create an `.envrc` file for the directory we would like to scope the environment variables to.
Say we create it for the directory `~/project`.

```bash
echo export FOO='I love Linux!' >> ~/project/.envrc
```

You will then receive a warning that the current `.envrc` wasn't read; `direnv` will block loading `.envrc` every time it detects changes which were not explicitly allowed. Run:

```bash
direnv allow ~/project
```

and voilà!, you now have a directory-scoped environment.

Remember when I told you that '`direnv` will block loading `.envrc` every time it detects changes which were not explicitly allowed'? This isn't limited to newly introduced changes, the whole file will be unauthorized. So when you

```bash
echo export BAR='It is actually called GNU/Linux!' >> ~/project/.envrc
```

you will have to run `direnv allow ~/project` again, even to access `$FOO`. Kinda boring, but biased towards safety.

Every time an `.envrc` is loaded, direnv will output a message with the file path and also the names of the variables loaded, so you don't need to worry about forgetting your setup. It will also tell you whenever an environment was unloaded.

That's it, pretty straightforward and I hope you find it as convenient as I did.