+++ title = "Environment Variables Made Easy" author = ["Elia el Lazkani"] date = 2025-02-20 lastmod = 2025-02-20 tags = ["env", "environment-variable", "envrc", "direnv", "dev", "developement"] categories = ["misc"] draft = false +++ If you've written software in the last decade, then you're probably familiar with the current technologies at play. You write your code, locally, in your IDE, build and test it. You've made your _commit_ and pushed it to the revision control system server and created a _pull request_. Pipelines started, code built, unit tests ran, magic all over and now it's deployed in _staging_. Once the code lives in _staging_ long enough to build trust in its performance it goes to _production_. This is in a nutshell how it looks like. The big elephant in the room is, of course, that all of these different environments are, well... different ! This means that the values I used to test my code locally is different than the values used to test in the pipeline, for security reasons. The same goes for every single environment. Configuration files could solve a lot of these issues but, as we all know, they don't solve all of them. Another solution is to use _environment variables_, which could be easily injected into scripts, environments and even containers. It's a win-win everywhere except managing them locally. You're probably thinking my `.profile` file looks like a mess. You'd be surprised to know that mine is empty, but how ? ## Direnv {#direnv} `Direnv` is [described](https://github.com/direnv/direnv) by the developers as > an extension for your shell. It augments existing shells with a new feature that > can load and unload environment variables depending on the current directory. It's as simple as that ! `Direnv` runs on most _operating systems_ and a wide variety of _shells_. The [installation](https://direnv.net/docs/installation.html) process is well documented and the same goes for configuring `direnv` to [hook](https://direnv.net/docs/hook.html) to your favorite _shell_. ## How does it work ? {#how-does-it-work} First, let's start by creating a _new_ project. ```shell $ mkdir project-1 $ cd project-1 ``` Now that we've created a project, let's create a `.envrc` file and populate it with the following. ```bash # Add build/bin to $PATH PATH_add build/bin # Export environment variables export DB_HOST="localhost" export DB_PORT="5432" export DB_USERNAME="dummy-user" export DB_PASSWORD="super-secret" ``` Once I save the file and exit the editor, I get greeted with a _lovely_ **error**. ```shell direnv: error ~/project-1/.envrc is blocked. Run `direnv allow` to approve its content ``` The reason for this is very simple. The `.envrc` file can do a lot, making it a security risk. This error is there to make sure that you check the `.envrc` and **only** allow `direnv` with _trusted_ `.envrc` files. I wrote this `.envrc` file, so I can safely trust it. But you can't ! ```shell $ direnv allow direnv: loading ~/project-1/.envrc direnv: export +DB_HOST +DB_PASSWORD +DB_PORT +DB_USERNAME ~PATH ``` This tells us that we've exported a list of environment variables. Let's check them out. ```shell $ env | grep DB_ DB_PORT=5432 DB_HOST=localhost DB_PASSWORD=super-secret DB_USERNAME=dummy-user ``` We've also used the `PATH_add` to add a project specific directory to our `PATH` allowing us to run the binaries directly without having to navigate to the _build_ directory.
Warning
It is very important, at this stage, for me to **warn** you about the dangers of committing your `.envrc` to your _revision control_. This bad boy's got _passwords_ in it ! Don't do it !