In real world development, we have to maintain environment variables e.g. target urls, service port number, database table name, etc. It would sound messy if we have to declare those variables every time we open an IDE, and would be more pain if we need to switch to another environment.

In this blog we will talk about 3 tools to make a deal with multiple environments easier.

  1. direnv to get folder ready for environment variables.
  2. devbox to make a folder isolated like a container for packages installed.
  3. gum to switch environment easily.

Plus a big advantage for team collaboration because they are file-based that we can push to the repo (with proper security management).


direnv for env

direnv is a tool to setup environment when access a prepared folder. For example, we enter a folder of Python and it automatically activates venv for us.

direnv setup

  1. We need to install direnv. In my setup, I installed it through homebrew.
  2. Once it's installed, add the hook into your shell file. In my setup that uses zsh, I just add this line into my ~/.zshrc.
eval "$(direnv hook zsh)"

And that's it. We are ready to initial my folder.

direnv usage

auto-scripts

Say we want to develop a Python app. Once we created venv, we have to activate it first, and deactivate at last, right?

With direnv we don't have to do so. Just enter the folder and it will activate and deactivate when leave the folder for us. Follow this.

  1. Create venv
    venv
  2. Create .envrc to activate venv. End with layout python
  1. Make sure we are in the folder and direnv allow to execute .envrc
    allow
  2. Leave the folder and see direnv deactivate the environment.
    leave

We can check Python venv with command which pip. The figure above represent my prompt showing venv from Oh-my-posh installed. Learn more about it from my dotfiles or https://ohmyposh.dev.

embedded env vars

Beside of that auto-script, the another main objective of direnv is to embed variables into the environment.

Let's say we embed a variable env into this folder. .envrc would look like this.

When we direnv allow and enter the folder, we will access the variable env. And get nothing when leave the folder.

Now we don't have to create and remove variables we declared over and over again.

Our lives go easier by +1 step.


devbox for packages

Move to another tool. devbox enables a directory installs packages locally

devbox setup

curl -fsSL https://get.jetify.com/devbox | bash

If that is the error Error: Unable to find nix startup file, please try installing Nix package manager.

sh <(curl -L https://nixos.org/nix/install) # for macos

devbox usage

First, init it

devbox init

then we can see a file "devbox.json".

Now we need to find the packages we want to install using devbox search like this.

devbox search package
devbox search package@version

Okay, we are gonna add Python 3.10 via

devbox add [email protected]

If this is a first time, devbox will install nix package manager if it's not installed yet.

Next time we can see the package has been being installed.

Then we should see the updated "devbox.json" like this.

The packages shows "[email protected]" (line 4) right there.

Next we start with the command below.

devbox shell # start shell

And we can see the python environment has been created. Basically venv folder named ".venv".

And exit at the end.

exit # exit shell

However the env is in .venv. We can custom the folder name by adding env (line 17-19) and apply it in init_hook (line 9) like this.

combo direnv & devbox

With devbox, we have no need to create venv beforehand because devbox will do it for us but we have to run shell and activate every time.

We can combo devbox with direnv to  run shell automatically with this command.

devbox generate direnv

.envrc generated this way will be like this.

At this step, we now control packages and access the environment at ease.


gum for multiple env

Okay we now are able to build an isolated workspace. How about maintaining multiple environment such as dev & prod?

Of course we have to prepare multiple files for each environment. And it will be good if we can switch from an environment to another.

We are talking about gum.

gum is a tiny tool to represent designated prompt for a specific task. It works great and flexible in operations using shell scripts. Here we will see how can we utilize gum to work with multiple environment.

gum setup

Install via homebrew.

brew install gum

or others by your preferences by visiting the link in references below.

gum usage

With gum alone, we can create a simple shell prompt like this.

And we will adapt with our setup earlier.

Say we have 2 environments; dev & prod. Also there are 2 env files like this.

And the structure becomes as below.

We will use a flag of devbox for direnv to select each of both files like this. That flag is --env-file followed by a target env filepath. It will turn out like this in .envrc

  • ls .envs to list all files in .envs folder.
  • gum choose to prompt choosing files from ls above.
  • --env-file to input chosen files from gum prompt.

And we run direnv allow. Finally we can select any env file to start an environment to work with.

select an env file
activate selected env

Repo

GitHub - bluebirz/sample-env: Demo direnv, devbox, and gum for isolated environments management
Demo direnv, devbox, and gum for isolated environments management - bluebirz/sample-env

References