140 lines
4.1 KiB
Markdown
140 lines
4.1 KiB
Markdown
|
+++
|
||
|
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 ?
|
||
|
|
||
|
<!--more-->
|
||
|
|
||
|
|
||
|
## 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.
|
||
|
|
||
|
<div class="admonition warning">
|
||
|
<p class="admonition-title"><b>Warning</b></p>
|
||
|
|
||
|
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 !
|
||
|
|
||
|
</div>
|
||
|
|
||
|
That's impressive and all but...
|
||
|
|
||
|
I know what you're gonna ask me next and here's the answer.
|
||
|
|
||
|
```shell
|
||
|
$ cd ..
|
||
|
direnv: unloading
|
||
|
```
|
||
|
|
||
|
and now...
|
||
|
|
||
|
```shell
|
||
|
$ env | grep DB_
|
||
|
$
|
||
|
```
|
||
|
|
||
|
Nothing at all. All variables have been unloaded automatically. They will be
|
||
|
loaded again the next time you navigate to the project's directory.
|
||
|
|
||
|
|
||
|
## Conclusion {#conclusion}
|
||
|
|
||
|
Next time you're working on your project, give `direnv` a try. It will change
|
||
|
the way you work for the better, I hope.
|
||
|
|
||
|
Happy Hacking !
|