I have been looking around for a replacement for the Docker development environment setup I have been using for some time. It worked well, but I had a dependency on Visual Studio Code and I was curious what else is there.
Several people pointed me to nix, but after spending some time with it, I realized that it is not for me. Here are a couple of reasons why:
It has a very steep learning curve and I could probably get something going relatively quickly, but sharing that with others would be a difficult task. One aspect of this is to have an simple way of doing this where we share these development environments in a team and everyone can contribute to it.
It is too complicated to have development environments with various specific versions of various tools. Each project has a list of tools that are required and sometimes, because of backwards compatibility certain (older) versions of these tools are required. On top of that, I like to be explicit about what versions of each tool go in the development environment and not roll the dice on what's latest (it's not recommended to do that with Docker images, why is it any better to do that with development tools and dependencies?)
Then I found out about devenv.sh, which simplifies some of the complexity from point 1 above (it is a wrapper around nix), but point 2 would still not be covered.
After some more searching, I found what seems the definite winner (for now): Jetify devbox (to not be confused with the Microsoft Dev Box). It ticked both points and it worked quite well (it is also a wrapper over nix). Here is how it works:
Installation
You need to install 3 tools:
nix (not nixOS, just the CLI and daemon) - on Arch Linux: pacman -S nix
direnv (for some folder magic, where the dev environment gets loaded automatically when you change directory to the project folder) - on Arch Linux: pacman -S direnv
devbox - on Arch Linux: paru -S devbox (only available on AUR repos, replace paru with your favorite AUR installer tool)
Usage
With these 3 in place, you navigate to a folder where you want to define the development environment with devbox and you get started with devbox init
This will create a devbox.json file in that folder with the following content:
{
"$schema": "https://raw.githubusercontent.com/jetify-com/devbox/main/.schema/devbox.schema.json",
"packages": [],
"shell": {
"init_hook": [
"echo 'Welcome to devbox!' > /dev/null"
],
"scripts": {
"test": [
"echo \"Error: no test specified\" && exit 1"
]
}
}
}
Now it is the time to add some packages. Let's say you want to install the latest version of kubectl 1.29 but you don't know which one is the latest. Let's find out!
➜ devbox-test devbox search kubectl
Found 20+ results for "kubectl":
* kubectl (1.30.2, 1.30.1, 1.30.0, 1.29.4, 1.29.3, 1.29.2, 1.28.4, 1.28.3, 1.28.2, 1.28.1 ...)
* kubectl-cnpg (1.23.3, 1.23.2, 1.23.1, 1.23.0, 1.22.2, 1.22.1, 1.22.0, 1.21.1, 1.21.0, 1.20.2 ...)
* kubectl-convert (1.30.2, 1.30.1, 1.30.0, 1.29.4, 1.29.3, 1.29.2, 1.28.4, 1.28.3, 1.28.2, 1.28.1 ...)
* kubectl-doctor (0.3.1, 0.3.0)
* kubectl-example (1.2.0, 1.1.0, 1.0.1)
* kubectl-explore (0.9.3, 0.8.3, 0.8.1, 0.7.2, 0.7.1)
* kubectl-gadget (0.31.0, 0.30.0, 0.29.0, 0.28.1, 0.28.0, 0.27.0, 0.26.0, 0.25.1, 0.24.0, 0.23.1 ...)
* kubectl-images (0.6.3, 0.6.1, 0.5.2)
* kubectl-klock (0.7.0, 0.6.1, 0.5.1, 0.5.0, 0.4.0, 0.3.2, 0.3.1)
* kubectl-ktop (0.3.7, 0.3.6, 0.3.5)
Warning: Showing top 10 results and truncated versions. Use --show-all to show all.
Great, 1.29.4 is the latest! Let's add it to our environment:
➜ devbox-test devbox add kubectl@1.29.4
Info: Adding package "kubectl@1.29.4" to devbox.json
Info: Installing the following packages to the nix store: kubectl@1.29.4
You can also skip passing a version if you don't care and you want always to get the latest. My advice is to care about the version, to avoid unnecessary surprises.
If you try to run kubectl right away, you will see that it is not found. Why? Well, you need to run devbox shell to access the development environment.
Or, even better, you let direnv take care of that. And devbox has built-in support for direnv, a match made in heaven!
➜ devbox-test devbox generate direnv
Success: generated .envrc file
Success: ran `direnv allow`
direnv: loading ~/Projects/personal/devbox-test/.envrc
direnv: using devbox
direnv: export +AR +AS +CC +CONFIG_SHELL +CXX +DEVBOX_CONFIG_DIR +DEVBOX_INIT_PATH +DEVBOX_NIX_ENV_PATH_f91609d578603651fe36552ea846f62b8e3d03b5514061f827e972fc226d38bd +DEVBOX_PACKAGES_DIR +DEVBOX_PATH_STACK +DEVBOX_PROJECT_ROOT +DEVBOX_SYSTEM_BASH +DEVBOX_SYSTEM_SED +HOST_PATH +IN_NIX_SHELL +LD +NIX_BINTOOLS +NIX_BINTOOLS_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu +NIX_BUILD_CORES +NIX_CC +NIX_CC_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu +NIX_CFLAGS_COMPILE +NIX_ENFORCE_NO_NATIVE +NIX_HARDENING_ENABLE +NIX_LDFLAGS +NIX_STORE +NM +OBJCOPY +OBJDUMP +RANLIB +READELF +SIZE +SOURCE_DATE_EPOCH +STRINGS +STRIP +__DEVBOX_SHELLENV_HASH_f91609d578603651fe36552ea846f62b8e3d03b5514061f827e972fc226d38bd +__structuredAttrs +buildInputs +buildPhase +builder +cmakeFlags +configureFlags +depsBuildBuild +depsBuildBuildPropagated +depsBuildTarget +depsBuildTargetPropagated +depsHostHost +depsHostHostPropagated +depsTargetTarget +depsTargetTargetPropagated +doCheck +doInstallCheck +dontAddDisableDepTrack +mesonFlags +name +nativeBuildInputs +out +outputs +patches +phases +preferLocalBuild +propagatedBuildInputs +propagatedNativeBuildInputs +shell +shellHook +stdenv +strictDeps +system ~PATH ~XDG_DATA_DIRS
This generated an .envrc file in the same folder (the config direnv needs) which looks like this:
# Automatically sets up your devbox environment whenever you cd into this
# directory via our direnv integration:
eval "$(devbox generate direnv --print-envrc)"
# check out https://www.jetpack.io/devbox/docs/ide_configuration/direnv/
# for more details
And it also ran direnv allow so that we allow direnv to automatically load the .envrc configuration when we change directory into this folder. Finally, go check out kubectl:
➜ devbox-test kubectl version --client=true
Client Version: v1.29.4
Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3
It's exactly the version we were expecting. From this point on, any package you add with devbox will be automatically loaded. You can commit these files with your project and anyone who has these tools installed will be able to benefit from a ready-to-go development environment with the right tools and their versions installed.
Integration with Visual Studio Code
And if you intend to use Visual Studio Code as you IDE, good news: there is an extension for devbox to make your life even easier. Just install the extension, open a folder that contains a devbox.json file and use the Devbox: Reopen in Devbox shell environment command. And in no-time you are ready to work on your project!
Conclusion
I like the simplicity of devbox and I hope it stays this simple. There are a few other things you can do with it, but it you look at the devbox.json reference, there isn't much more to it:
{
"packages": [] | {},
"env": {},
"shell": {
"init_hook": "...",
"scripts": {}
},
"include": []
}
Of course, devbox builds on the complexity of nix , but sometimes it is nice to not have to deal with that complexity and just get something simple and useful done!
Comments