Nix-shell: How to run `corepack enable` to install modern Yarn?

For modern versions of Yarn, the preferred installation is through Corepack, and Corepack is included by default with Node.js installs (>=16.10). See Installation | Yarn.

This is what I’ve tried to do corepack enable in default.nix , but it doesn’t work.

with import <nixpkgs> {};

stdenv.mkDerivation {
  name = "dev";
  buildInputs = [ nodejs-17_x ];
  postPhases = ''
    corepack enable
  '';
}

We’ll need a bit more than “doesn’t work” :slight_smile: Error messages/logs would be nice.

The preferred way with nix should probably be to use the package from nixpkgs, because it avoids any number of issues you’ll run into because other project’s package managers have no support for nixos: yarn.

If you really need to follow the upstream way, you’ll likely need to patchelf some things, and/or use buildFhsUserEnv[Bubblewrap]. Could you elaborate on why you need to do this? Maybe we can find some other solution.

1 Like

Hi @TLATER thanks for the reply!

Unfortunately, I don’t think we have a package for modern Yarn (aka Yarn berry, Yarn 2+) from nixpkgs.

The yarn package from nixpkgs is actually Yarn 1 (Classic). You can see the version number at here on the github repo.

It doesn’t throw any error after I run nix-shell with my default.nix. Is it possible to get the logs for the nix-shell command?

1 Like

corepack enable modifies installation directories, which means it tries to write to /nix/store/...nodejs-x.y.z/bin/, but that’s not allowed.

It only creates some symlinks, so what you can do is package those symlinks:

stdenv.mkDerivation {
  name = "corepack-shims";
  buildInputs = [ nodejs-17_x ];
  phases = [ "installPhase" ];
  installPhase = ''
    mkdir -p $out/bin
    corepack enable --install-directory=$out/bin
  '';
}

You can then use that derivation as a build input for some other derivation, and the corepack shims will be available in $PATH.

Note that corepack downloads package managers to ~/.node/corepack, but $HOME is set to /homeless-shelter inside Nix builds. So when using the corepack shims, you may have to give it a writable home directory by doing something like: export HOME=$TMPDIR

EDIT: You can apparently also set COREPACK_HOME if you don’t want to modify HOME.

EDIT 2: Corepack downloading stuff also makes your build impure. Not sure what the best approach to using corepack is, really.

3 Likes

It might be best just to package a more recent version of yarn from source at that rate. I wonder why it isn’t packaged yet, a cursory glance shows no PRs for it.

1 Like

This confused me as well at first, but then I read in the Yarn docs that recent versions of Yarn 1.x can install newer versions itself. So that might be a reason why there is only the 1.x package in nixpkgs.

Anyway, here’s what works for me in shell.nix:

let
  pkgs = import (fetchTarball https://channels.nixos.org/nixpkgs-22.11-darwin/nixexprs.tar.xz) {};
  nodejs = pkgs.nodejs-16_x;
  yarn = pkgs.yarn.override { inherit nodejs; };

in pkgs.mkShell {
  buildInputs = [
    nodejs
    yarn
  ];

  shellHook = ''
    yarn set version 3.x
  '';
}

Here’s how to use devenv:

{ pkgs, ... }: {
  languages.javascript.enable = true;
  languages.javascript.package = pkgs.nodejs_18;
  languages.javascript.corepack.enable = true;

  processes.serve.exec = "yarn parcel:serve";
}

And in your package.json:

{
  "engines": {
    "yarn": "^3.6.0"
  }
}