How to use `pnpm` with recent nodejs?

I’m trying to use pnpm (nodePackages.pnpm) with nodejs 18. I tried using a shell.nix, a flake.nix and nix-shell -p nodePackages.pnpm. In all three scenarios it uses nodejs 14.

I tried to adapt this workaround for yarn and added an overlay (see below) but the result was, that pkgs.nodePackages only contained pnpm and nothing else. Also, it still used nodejs 14.

let
    # Rolling updates, not deterministic.
    pkgs = import (fetchTarball("channel:nixpkgs-unstable")) { inherit overlays; };

    overlays = [
        (self: super: {
            nodePackages.pnpm = super.nodePackages.pnpm.override {
                nodejs = pkgs.nodejs-18_x;
            };
        })
    ];
in pkgs.mkShell {
    name = "nix-shell";

    packages = with pkgs; [
        bashInteractive
        nodejs
        nodePackages.pnpm
    ];
}

Something strange I noticed: As soon as I add nodePackages.pnpm to my shell.nix, flake.nix or nix-shell -p, the npm command (not Pnpm) also uses node 14 instead of node 18.

To see the version it uses I added the following script to my package.json

    "nv": "node --version",

so that I could get the node version using pnpm nv or npm run nv.

Can anyone please help me to create an overlay that makes pnpm use node 18?

I use a little different override:

let nodejs = pkgs.nodejs-16_x; in

let pnpm = pkgs.nodePackages.pnpm.override {
  nativeBuildInputs = [ pkgs.makeWrapper ];

  preRebuild = ''
    sed 's/"link:/"file:/g' --in-place package.json
  '';

  postInstall = let
    pnpmLibPath = pkgs.lib.makeBinPath [
      nodejs.passthru.python
      nodejs
    ];
  in ''
    for prog in $out/bin/*; do
      wrapProgram "$prog" --prefix PATH : ${pnpmLibPath}
    done
  '';
}; in

pkgs.mkShell {
2 Likes

You should be able to use pkgs.node-18_x.pkgs.pnpm to get a pnpm that uses the node version you want:

❯ nix shell nixpkgs#nodejs-18_x.pkgs.pnpm -c pnpm exec node --version
v18.9.1
❯ nix shell nixpkgs#nodejs-16_x.pkgs.pnpm -c pnpm exec node --version
v16.17.1
1 Like

Also found out that if you’re using this kind of overlay

overlays = [ (self: prevPkgs: {
    nodejs = prevPkgs.nodejs-16_x;
}) ]

nixpkgs.nodePackages like pnpm will be using that version of nodejs:

pnpm node --version v16.17.1
1 Like

I used this:

pnpm = super.linkFarm "pnpm" [ { name = "bin/pnpm"; path = "${self.nodejs-18_12_1.pkgs.pnpm}/lib/node_modules/pnpm/bin/pnpm.cjs"; } ];

I actually used this instead:

  nodePackages = super.nodePackages.override {
      nodejs = nodejs-18_12_1;
    };

First of all, thank you all for your answers!

The unstable channel now uses node 18 for pnpm so my issue is technically solved for now.

However I’d still like to learn how I could solve it myself for the future. To test it, I replaced the line

pkgs = import (fetchTarball("channel:nixpkgs-unstable")) { inherit overlays; };

with

pkgs = import (fetchTarball("https://github.com/NixOS/nixpkgs/archive/refs/heads/nixos-22.05.tar.gz")) { inherit overlays; };

so it uses the 22.05 channel, where pnpm still uses node 14. Then I tried our your solutions:

@kamilchm Your solution seems to be the only one that really works. Could you please explain how you knew how to do this?

@khaled your command works but how would I use it in a shell.nix?

@tennox, this does not work for me when using channel 22.05. Are you sure this should work or was it just a coincidence that unstable used node 16 at the same time? When I use this overlay with 22.05 I still get node 14…

@fzakaria these solutions only “work” for me for the unstable channel. I suspect that is because the unstable channel already uses node 18. Are you sure it also works on 22.05? I can’t get it to work like that.

The link farm works with any NodeJS since it just creates symlinks

I am missing the last step for the override solution…

It’s installing the node package but doesn’t seem to have a top level /bin so it’s not in my $PATH

Try this als:

  pnpm = super.nodePackages.pnpm.override {
      # set the node version to whatever you want
      nodejs = nodejs-18_12_1;
  };

I am not sure why i can’t override nodePackages to apply to all of the packages.

Yes I’m sure the overlay method works, I use it almost every day for projects with node 18 and 16, e.g. based on this template:

(You obvioualy need to uncomment to change version)

your command works but how would I use it in a shell.nix ?

Change the original shell.nix you shared:

    packages = with pkgs; [
        bashInteractive
        nodejs
        nodejs.pkgs.pnpm   # this line changed
    ];