Nix and the nix-shell for easily redistributable scripts

In the discussion at lobsters and the article linked in there, I made a comment how one could use Nix and the nix-shell in order to have easily redistributable scripts. This post expands on it.

Nix is hermetic in the sense that its “packages” do not use dependencies from the outside and its packages do not affect the system. Furthermore, one can have multiple versions of a package in the systems at the same time.

I was explicitly talking about scripts, in a way to enable running them, such that no installation of dependencies is needed prior to running the script.

To illustrate the point, let’s say on has a script written in fish, which relies on ripgrep and dust. Normally, the script would begin with #!/usr/bin/env fish. Now, that is quite a portable way of writing the script and great practice. However, for our goal of including all the dependencies, we need more. To that end, one can use the nix-shell in the shebang line, that will then be used to fetch all the dependencies (from Nix, if they are available in the nixpkgs:

#!/usr/bin/env nix-shell
#!nix-shell -I nixpkgs=
#!nix-shell -i fish
#!nix-shell -p fish -p ripgrep -p dust

The first line is the regular shebang invocation which tell the system to use the nix-shell as the interpreter. The second line is read by the nix-shell when it starts interpreting the script, and -I option is there to pin the dependencies to a particular “release” of nixpkgs. The third line (the one with -i) tells the nix-shell that the actual interpreter is fish. Lastly, the fourth line references the dependencies. The particular versions will be the ones defined by the nixpkgs-channel from the given revision in -I.

The beauty of this approach is that one could also do it with perl or python scripts, pulling their dependencies (as long as they are in nixpkgs).