はじめに

昨年からパッケージ管理ツールとして Nix を使っています。現在、プロジェクトはすべて Nix を利用しています。

Web 開発では、Node.js の LTS バージョンをよく使います。Nix は NPM パッケージを nodePackages として提供していますが、最新の Node.js を使うようになっていますので、以下のようにすると Node.js を二重に取得してしまいます。

1
2
3
4
packages = [
  pkgs.nodejs_22
  pkgs.nodePackages."@angular/cli"
]

最近、この問題を解決する良い方法を見つけました。

overlay を使ってみる

Nix には overlay という機能があり、ミドルウェア関数のようなものです。これで pkgs.nodejspkgs.nodejs_22 に設定できるのです。

以下に例を示します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
  inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
  outputs = { nixpkgs, ... }:
    let
      pkgs = import nixpkgs {
        system = "aarch64-darwin";
        overlays = [
          # 後で説明します
          (final: prev: {
            nodejs = prev.nodejs_22;
          })
        ];
      };
    in
    {
      devShells.aarch64-darwin.default = pkgs.mkShell {
        packages = [
          # overlay によって pkgs.nodejs_22 と同じになった
          pkgs.nodejs
          # これも pkgs.nodejs_22 を使用するようになる
          pkgs.nodePackages."@angular/cli"
        ];
      };
    };
}

overlay は高階関数です。すなわち、関数を返す関数です。

1
2
3
final: prev: {
  nodejs = prev.nodejs_22;
}

読みづらいかもしれないので、同等の JavaScript コードを示します。

1
(final) => (prev) => ({ nodejs: prev.nodejs_22 });

必ず覚えておきたい引数は prev です。普通に nixpkgs に渡された引数だ、と考えていいでしょう。final は理解する必要はありません。「そんなものがあるらしい」くらいに覚えておけばそれで十分です。

バージョンを確認

node コマンドと ng コマンドの両方が、同じ Node のバージョンを報告することを確認しましょう。まず node から確認していきます。

% node -v
v22.14.0

本記事執筆時点で最新のバージョンは v23.9.0。想定通り、overlay が効いていますね。

続いて、ng コマンドを実行し、報告されるバージョンを確認します。

% ng v

[...略...]

Angular CLI: 19.1.8
Node: 22.14.0
Package Manager: npm 10.9.2
OS: darwin arm64

はい、期待通りの結果ですね。

終わりに

Nix の overlay 機能を利用して、Node.js のバージョン不整合を解決する方法を解説しました。

ここまで読んでいただきありがとうございます。