Skip to content

Tools Version Manager

The nix-versions tool manager is so simple that it does not exist. It is more of a pattern of usage when combined with nix shell and direnv.

The idea is simple: No nix-wizardry required, just use plain-text files to specify your tool requirements and let nix-versions produce output that nix shell and direnv can use to give you a stable development environment.

If you already know Nix, and want to use pinned-version packages as inputs for your own Nix Flake or integrate with state-of-the-art Nix environments like devenv or devshell, NixOS/nix-darwin/home-manager or any other nix module class, see our flake generator service.

As a Tools Version Manager, the pattern presented on this page can replace 90% of what tools like asdf-vm do, but with all the benefits you can get from Nix: All installable tools from Nixpkgs at your fingertips, Reproducibility, Security Checksums, Sandboxed Builds, Remote Builders, Caching, etc. And of course, pinned version packages by nix-versions.

If you are new to Nix but have used other version managers like nvm, rvm, asdf, mise we want to provide you with an integrated toolset that lets you take advantage of Nix without mandating you to learn the nix language. By editing plain-text files and reusing your existing .ruby-version, .node-version, etc files, you can cover most of your needs.

If you already have Nix and direnv installed, you can quickly get an environment ready in no time. Note that you don’t even need nix-versions installed locally for this to work. Because the endpoint already resolves the nix installables for you.

Terminal window
# Place this on your .envrc
source_url "https://nix-versions.oeiuwq.com/use_nix_tools.sh/go/ruby" HASH

Where HASH can be obtained with:

Terminal window
direnv fetchurl "https://nix-versions.oeiuwq.com/use_nix_tools.sh/go/ruby"

You can obtain package updates by doing direnv reload.

By playing well with others. Following the UNIX philosophy of doing just ONE thing (listing package versions) and producing plain-text output that can be used by other programs to become part of something bigger.

By using the --installable (short: -i) option, nix-versions can produce a list of Nix Installables that can be read by nix shell.

Terminal window
nix-versions --installable go@1.24.x ruby@latest

Output:

nixpkgs/de0fe301211c267807afd11b12613f5511ff7433#go_1_24
nixpkgs/0d534853a55b5d02a4ababa1d71921ce8f0aee4c#ruby_3_4

Reading package specs from a plain-text file

Section titled “Reading package specs from a plain-text file”

Instead of giving package specs as command line arguments you can use the --read (short -r) option for reading them from a file.

The file name is not special to nix-versions, but we use the convention of having a .nix_tools file.

Terminal window
nix-versions --read .nix_tools --installable

The .nix_tools file can look like this:

# shell-like comments are ignored.
# You can use `pkg@version` as in nix-versions command line
ruby@latest # same as `ruby@` or `ruby@*`, ie. no version restriction.
# You can use spaces/tabs after the package name, just like .tool-versions files from asdf.
# And it also looks much cleaner.
go >= 1.24 <1.26 # white space/tabs are not significant.
nodejs .node-version # read version constraint from an existing file.

As you can see from the previous example, you can reuse your existing .ruby-version, .node-version, .tool-versions, etc files that might be already in use in your project.

Now that you have some files like .nix_tools, .node-version from the previous examples, you are ready to enter a nix development shell containing those tools, pinned to their constrained versions.

Terminal window
nix shell $(nix-versions -ir .nix_tools)

Now you might want to load the environment into your existing shell automatically, every time you enter your project directory. The right tool for doing this is direnv.

All you need now is to create the following file $HOME/.config/direnv/lib/use_nix_tools.sh. This file will install a function that all your projects can use to load their respective environment.

Terminal window
mkdir -p ~/.config/direnv/lib
# You can always inspect the downloaded function before installing it
curl "https://nix-versions.oeiuwq.com/use_nix_tools.sh" -o ~/.config/direnv/lib/use_nix_tools.sh

Then, on your project directory, besides your .nix_tools file, create an .envrc file that will be detected by direnv.

.envrc
use nix_tools

And you are set! Just direnv allow and enjoy using your tools.

The Nix ecosystem has much more advanced development environments than those produced by nix shell. A couple of them are devenv and devshell, that provide more advanced features than simply loading environment variables.

See our flake generator documentation for how to use pinned packages with these tools.

Contribute Community Sponsor