Joseph's Blog

Using overrideAttrs on Nixpkgs with buildNpmPackage

In NixOS, overrideAttrs allows to customize the arguments passed to stdenv.mkDerivation. This is useful for things like modifying src to change the version of a package, or adjusting the flags used to build a package:

final: prev: {
  zig_0_12 = prev.zig_0_12.overrideAttrs (_: {
    # workaround for https://github.com/NixOS/nixpkgs/issues/317055
    strictDeps = !prev.stdenv.cc.isClang;
  });
}

However, this method does not (directly) work for packages built with wrappers around mkDerivation. For example, buildNpmPackage acts as wrapper around mkDerivation. Calling overrideAttrs will overide parts of mkDerivation, but will not allow for the modification of arguments passed to buildNpmPackage. This makes changes to a file like package-lock.json (using patches or a postPatch script) impossible, as it’s too late to modify the npmDeps that have been fetched and passed to mkDerivation at this point. Although though patches can be used to modify the package-lock.json file present in src, the NPM dependencies have already been fetched and modifications to package-lock.json will have no effect.

In other words, overrideAttrs affects mkDerivation, not buildNpmPackage or other helpers

Since buildNpmPackage cannot be modified, its output (which is passed to mkDerivation) can be modified instead. npmDeps is a derivation created by fetchNpmDeps; to override it, fetchNpmDeps can be provided with new arguments, such as patches that are not present in the original buildNpmPackage invocation of fetchNpmDeps.

zwave-js-server = prev.zwave-js-server.overrideAttrs (old: rec {
  # to update: run `npm update` in the zwave-js-server repo (or npm install --only-lock-file)
  # copy package-lock.json to the patches dir
  # update the npmDepsHash with `nix run nixpkgs#prefetch-npm-deps package-lock.json`
  patches = (old.patches or [ ]) ++ [
    ./zwave-js-server/logging-unknown-type.patch
  ];
  postPatch = ''
    cp ${./zwave-js-server/package-lock.json} ./package-lock.json
  '';
  npmDeps = final.fetchNpmDeps {
    inherit (old) src;
    inherit postPatch;
    hash = "sha256-ECdmSOugInD7JFEvjkeQfMyrJzKhOIQHs3MwOFEpoSk=";
  };
});

The goal of this override is to use a custom version of npmDeps with updated dependencies. A newer package-lock.json is provided (replacing the old one present in src), along with a new hash. This new hash is calculated by running nix run nixpkgs#prefetch-npm-deps package-lock.json with the new/ updated package-lock.json file.

Finally, a patch is applied to src—this is the more usual use of overrideAttrs, providing an additional patch to apply against src. This patch will be applied after fetching the NPM dependencies (which is done by fetchNpmDeps, prior to running mkDerivation).

To further update the dependencies, update the package-lock.json file (using npm update or similar), then update the hash with nix run nixpkgs#prefetch-npm-deps package-lock.json.

#Nix