Automate Project Environments with Devbox and Direnv

The challenge of managing multiple projects in the same operating system has been met with many different solutions over the years. We've progressed from virtual machines (VirtualBox) to container systems (Docker), and even isolated shells (nix-shell). We built Devbox to make isolated shell environments easy to learn, use, and configure. The combination of easy shell environments with Devbox, combined with convenient environment switching with Direnv makes it simple to manage multiple projects without having their setups interfere or leak into one another.

In this blog we’re going to explore why having an isolated environment is useful, explain why setting up an environment with Direnv can be tough, and showcase an example with our optimal combination: Direnv + Devbox for a sample NodeJS application.

Why have an isolated environment per project?

There are 4 main reasons why an isolated environment is needed:

  • Dependency version mismatching: Each application has its own dependency packages meaning two applications may need two different versions of the same dependency. For example, an enterprise developer may use a stable version of NodeJS for work projects but use an edge version of NodeJS which has newer features for a personal project. In this case, some languages have a version manager (e.g., nvm for NodeJS) but with Devbox there is no need to install a version manager per programming language.
  • Application settings: Each stack might have at least one or two settings that may be different from other applications. For example, you might have DATABASE_PORT and DATABASE_PASSWORD as env variables that are specific to your app.
  • Secrets: Similar to applications settings, your app might have secrets that are required to access 3rd party tools and platforms such as API_KEY and API_SECRET
  • Compiler options: Depending on the programming language, your app might need to have specific compiler options to compile for a target CPU architecture, or look for libraries in a specific directory. For example, in C++ you may need to setup LDFLAGS or CPPFLAGS and in Java, you may need to setup JAVA_HOME.

The listed items above are not the only reasons why you might want to have an isolated environment. Based on the use case, there might be other motivations but regardless, setting up isolated environments can be cumbersome and time-consuming. Let’s explore setting up an environment with Direnv below.

Direnv

Direnv is a tool that automates configuring environments on a per-directory basis. So that when you cd into a directory, it triggers Direnv to activate a pre-configured environment. It makes it very convenient in managing different environments and easily switching between them just by doing cd dir_name .

The problem with using Direnv is that despite it being a very useful tool, its setup requires investing time and getting over the Nix ecosystem's learning curve. In addition to that, each project requires the developer to spend some time writing a .envrc file and maintaining it as the requirements for the project change.

Automatic Devbox Environments with Direnv

We at Jetpack loved the convenience of Direnv. So following our philosophy of simplifying complicated tools to make them easy to adopt, we developed an integration between Devbox and Direnv. With this integration, there is no need to setup any .envrc files to use Direnv. Just having Direnv and Devbox installed on your system is enough to initiate a project environment with Devbox, add its dependencies, and integrate it with Direnv just by running devbox generate direnv . That way, whenever you cd to a Devbox + Direnv project, the Devbox environment is automatically setup and ready to go.

Take a look at the example below to see the simple steps required to setup a sample project with Devbox and Direnv:

  1. Make sure to have both Devbox and Direnv installed.
  2. In a project directory (or empty dir) run devbox init
  3. Add dependencies to Devbox. For example, devbox add nodejs yarn
  4. Add Direnv integration devbox generate direnv

That’s it! You have a working Devbox environment integrated with Direnv. Now any change done to your Devbox environment via devbox.json is applied by Direnv. Now that we’ve setup the environment, let’s see how we can automate starting a sample NodeJS project:

  1. Start a yarn project by running yarn init and follow the prompts.
  2. Add a small web server to your NodeJS project yarn add http-server.
  3. Edit the "init_hook" section of devbox.json so that it looks like the following:
{
  "packages": [
    "nodejs@latest",
    "yarn@latest"
  ],
  "shell": {
    "init_hook": [
      "yarn install",
      "yarn run http-server"
     ]
  }
}

This sets up this project so that every time you cd into this project, all NodeJS dependencies get installed and http-server runs. To test this, cd .. and then cd back into your project directory and see how Direnv setups up your Devbox environment and runs http-server. Use Ctrl+C to stop http-server.

Next Steps

Devbox makes creating and working in isolated dev environments simple and easy. Direnv makes switching between multiple environments convenient. So combining the two provides a great experience for setting up and using your dev environments.

We liked using Direnv so much that we started using it in our development of Devbox. In fact, we use both Devbox and Direnv to develop Devbox! To see it in action check out devbox.json and .envrc files in our Github repo.

Stay up to Date with Jetify

If you're reading this, we'd love to hear from you about how you've been using Devbox for your projects. You can follow us on Twitter, or chat with our developers live on our Discord Server. We also welcome issues and pull requests on our Github Repo.