Go Tool: direnv
Tags: go, productivity
Published: 2021-01-24 22:14:20

`direnv` is definitively a Go tool, in the context of _it is_ written in Go, but it is not a _development_ tool like the ones I covered before in previous posts (like [versions](https://mariocarrion.com/2020/05/14/2020-introducing-versions-go-tool.html), [ifacecodegen](https://mariocarrion.com/2019/07/17/golang-tools-ifacecodegen.html), [counterfeiter](https://mariocarrion.com/2019/06/24/golang-tools-counterfeiter.html) or [retool](https://mariocarrion.com/2019/04/17/golang-tools-twitchtv-retool.html)), **however** it is one of those tools that you _should_ consider using when developing programs (in any programming language really, not only Go), specially if you build programs that have different binary dependencies or any other dependencies that could be configured via environment variables.

### Whats is _direnv_?

According to the official page:

> direnv is 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**.

(Emphasis mine)

The key takeaway of that description is the powerful ability to load/unload environment variables depending on where you're _are located at_ when interacting with your terminal.

### Why is using _direnv_ relevant?

Consider the following hypothetical scenario: You're building _something_ that happens to depend on a tool to generate some code, let's call it `tool (v1)`, after a while you starting working on a new project, this new project uses the same tool but a different version `tool (v2)` but compared to v1 it generates code in a different way. Having `v1` installed will conflict with `v2` (and the same will apply the other way around) because both tool generate incompatible artifacts.

In the context of Go, handling dependencies like that is easily managed using [Go Modules](https://mariocarrion.com/2019/10/28/golang-migrating-to-go-modules.html), however what about our actual runtime needs? What do I mean by that? If we depend on `tool (v1)` then we need to have it installed and available in our `PATH`, same story with `tool (v2)`.

How can we handle this conflict? More importantly, how do we go about having those tools _sandboxed_?

### Introducing _direnv_

This is where `direnv` really shines, it allows us to _sandbox_ things that happen to use environment variables as configuration options, the most common example of this is creating concrete `PATH` variables to happen to be relative to your working directory, the idea is that only the binaries installed _inside_ our folder will be used. Having this configuration allows `direnv` to clearly define a boundary that is only applicable to the folder we are in.

The official [Github repository](https://github.com/direnv/direnv) includes specific steps for installing it and using it, it works like this:

1. Create a new `.envrc` file wherever you want the configuration to apply for current directory and other subdirectories, and
1. Configure that `.envrc` to define the directives you want to apply.

For example, using our hypothetical scenario from above, when working on `project1` (which uses `tool (v1)`), on the parent directory we could define the `.envrc` as following: 

```sh
PATH_add bin
export GOBIN=$PWD/bin
```

This indicates `direnv`:

1. To update `PATH` to point to `bin/` in the current working directory and,
1. To also export `GOBIN` to point to that path as well.

The idea is that when we `go install` `tool (v1)` it will get installed under `bin/` **and** also when we try to execute it will be available under the same path.

If we create a similar `.envrc` for `project2` (which uses `tool (v2)`), the results will be similar. In practice what this means is that now both projects can refer to different versions of the same tool without conflicting to each other. **That** is a powerful feature.

### Final thoughts

I can't recommend `direnv` enough, it's such a simple **yet** powerful tool that should improve your development experience.

Give it try, you won't be disappointed.