Specifying Package Version in `shell.nix`?

(These 4 steps should explain the situation)

  1. Installing latest nodejs on command line? easy nix-env -i nodejs
  2. Using latest nodejs in shell.nix? easy
let
    # (using niv for pinned versions)
    sources = import ./nix/sources.nix;
    normalPackages = import sources.nixpkgs {};
in
    normalPackages.mkShell {
        buildInputs = [
            normalPackages.nodejs
        ];
    }
  1. Installing specific nodejs version on command line? easy nix-env -i nodejs-14.5.0
  2. Using specific nodejs version in shell.nix?
# ... no idea

How can the version be specified inside a shell.nix?

(version being one of the versions from nix-env -q --available nodejs)

What I have tried (over the course of ~1 week)

I know nix is hard and all but dang; just learning how to specify a version in nix is taking about as long as learning all of Vue, React, and Ruby combined.

2 Likes

nix-env without -A (--attr) searches all packages for one with matching name attribute. It is better to use attribute paths (i.e. attribute name in all-packages.nix and so on) to refer to package since it avoids the need to evaluate all the packages and possible ambiguities. You can print the attribute paths by adding -P (--atrr-path) to nix-env.

$ nix-env -qP --available nodejs
nixos.nodejs       nodejs-10.18.1
nixos.nodejs-10_x  nodejs-10.18.1
nixos.nodejs-12_x  nodejs-12.14.1
nixos.nodejs-13_x  nodejs-13.6.0
$ nix-env -iA nixos.nodejs-13_x

The attribute paths are what is used in Nix expression so you would use normalPackages.nodejs-14_x.

If you really wanted to use the derivation names, you would do something like lib.filterAttrs (a: p: lib.isDerivation p && p.name == "nodejs-12.14.1") pkgs but you would need to handle recursion, packages that fail to evaluate and other issues. Using attribute is much better choice as described above.

3 Likes

That worked wonderfully, thank you! My first project setup with nix is complete :confetti_ball:

Answer to: 4. Using specific nodejs version in shell.nix ?

And, just to be clear to anyone else stumbling across this thread, the exact/literal shell.nix looks like:

let
    # (using niv for pinned versions)
    sources = import ./nix/sources.nix;
    normalPackages = import sources.nixpkgs {};
in
    normalPackages.mkShell {
        buildInputs = [
            normalPackages.nodejs-12_x
        ];
    }

Iā€™m still not used to dashes being allowed in names.

Also for anyone else using niv, if you get errors when it works on command line, you might need do

# careful with the rm
rm -rf ./nix
niv update nixpkgs -b nixpkgs-unstable
niv init
1 Like