Nixを理解する
「Nix」という名前を聞いたことがあるだろうか。dotfiles管理のHome-Manager、開発環境構築のdevenv、あるいはNixOSというLinuxディストリビューション。これらはすべて「Nixエコシステム」の一部だ。
dotfiles管理のモダンプラクティス2026でHome-Managerを紹介したが、その背後にある思想を理解しないと、なぜわざわざ学習コストの高いNixを使うのかがわからない。この記事では、Nixの核心にある「純粋関数型パッケージ管理」という思想と、それが解決する問題を掘り下げる。
なぜNixが存在するのか
従来のパッケージ管理には、長年解決されていない問題がある。
依存関係地獄(Dependency Hell) - パッケージAはライブラリXのv1.0を要求し、パッケージBは同じライブラリXのv2.0を要求する。両方を同時にインストールできない。
環境差異 - 「私のマシンでは動く」問題。開発環境、CI環境、本番環境で微妙にバージョンが異なり、再現不能なバグが発生する。
壊れるアップグレード - パッケージを更新したら、依存していた別のパッケージが動かなくなった。しかも元に戻す方法がない。
暗黙の依存関係 - ビルドが成功したが、実は環境にたまたま入っていたツールに依存していた。別の環境では動かない。
これらの問題の根本原因は、従来のパッケージ管理がミュータブル(可変) であることだ。/usr/bin/pythonというパスは一つしかなく、アップグレードすると上書きされる。
Nixは、この問題を**イミュータブル(不変)** なアプローチで解決しようとしている。
Nixとは何か:3つの顔
「Nix」という言葉は、文脈によって3つの異なるものを指す。

Nix言語
Nixの基盤にあるのは、純粋関数型の設定記述言語(DSL)だ。JSONに似た見た目だが、関数、変数、条件分岐、遅延評価を持つ。
{
# 基本的な属性セット(JSONのオブジェクトに相当)
name = "my-project";
version = "1.0.0";
# リスト
dependencies = [ "nodejs" "git" ];
# 条件分岐
shell = if pkgs.stdenv.isDarwin then "/bin/zsh" else "/bin/bash";
# 関数
greet = name: "Hello, ${name}!";
}
この言語の特徴は純粋性だ。同じ入力には必ず同じ出力が返る。副作用がない。これがNixの再現性を支える根幹になっている。
Nixパッケージマネージャ
Nix言語で書かれたパッケージ定義を解釈し、実際にビルド・インストールを行うツール。2003年にEelco Dolstraによって開発された。
従来のパッケージマネージャ(apt、Homebrew等)とは根本的に異なるアプローチを取る。詳細は後述する。
NixOS / Home-Manager / Flakes
Nixエコシステムの上に構築されたツール群:
- Nixpkgs - 100,000以上のパッケージを含むリポジトリ
- NixOS - OS全体をNix言語で定義するLinuxディストリビューション
- Home-Manager - ユーザー環境(dotfiles、ユーザーサービス等)をNixで管理
- Flakes - 依存関係のロックと再現性を強化する仕組み(実験的だが事実上の標準)
重要なのは、NixOSを使わなくてもNixは使えるということだ。macOSやUbuntuにNixパッケージマネージャだけをインストールし、Home-Managerでdotfilesを管理する、という使い方も可能。
純粋関数型アプローチ:なぜ「関数」なのか
Nixの核心を一言で表すと「パッケージを関数の戻り値として扱う」ということだ。
従来のパッケージ管理では、apt install firefoxを実行すると、システムのどこかにFirefoxがインストールされる。そのパスは固定で、バージョンを上げると上書きされる。
Nixでは、パッケージは「入力(ソースコード、依存関係、ビルドスクリプト等)を受け取り、出力(ビルド成果物)を返す関数」として定義される。
パッケージ = f(ソースコード, 依存関係, ビルドスクリプト, ...)
関数型プログラミングの「純粋関数」と同様に、同じ入力からは必ず同じ出力が得られる。これがNixの再現性の源泉だ。
Nix Storeの仕組み:ハッシュが保証する再現性
Nixのパッケージは、/nix/store/という特殊なディレクトリに格納される。
/nix/store/5rnfzla9kcx4mj5zdc7nlnv8na1najvg-firefox-120.0/
この5rnfzla9...という文字列は、パッケージのすべての入力から計算されたハッシュだ。これはContent-Addressable Storageと呼ばれる方式で、データの内容からアドレスを決定する。

ハッシュの計算には以下が含まれる:
- ソースコード
- ビルドスクリプト
- 依存パッケージ(それぞれのハッシュ)
- 環境変数
入力が1ビットでも変われば、ハッシュも変わり、出力パスも変わる。
この仕組みがもたらす帰結:
複数バージョンの共存
/nix/store/abc123...-python-3.9.0/
/nix/store/def456...-python-3.10.0/
/nix/store/ghi789...-python-3.11.0/
パスが異なるため、異なるバージョンが干渉せず共存できる。あるプロジェクトはPython 3.9を、別のプロジェクトはPython 3.11を使う、ということが自然にできる。
アトミックなアップグレードとロールバック
パッケージを更新しても、古いバージョンは/nix/store/に残っている。問題があれば、参照先を戻すだけで以前の状態に復帰できる。アップグレードの途中で電源が落ちても、システムが中途半端な状態になることはない。
再現性の保証
同じflake.lock(依存関係のロックファイル)からは、どのマシンでも同じパッケージがビルドされる。「私のマシンでは動く」問題が原理的に発生しない。

Nixが有効なユースケース
Nixの学習コストは高い。どんな場面でその投資が報われるのか。
開発環境の統一
チームメンバー全員が同じ開発環境を使うことを保証できる。
# flake.nix
{
outputs = { self, nixpkgs }: {
devShells.default = nixpkgs.legacyPackages.x86_64-linux.mkShell {
buildInputs = [
nixpkgs.legacyPackages.x86_64-linux.nodejs_20
nixpkgs.legacyPackages.x86_64-linux.yarn
nixpkgs.legacyPackages.x86_64-linux.postgresql_15
];
};
};
}
新しいメンバーがジョインしたら、nix developを実行するだけで環境が整う。READMEに「Node.js 20をインストールしてください」と書く必要がない。
CI/CDでの再現性
ローカルで通ったテストがCIで落ちる、という問題を減らせる。CIもローカルも同じNix定義から環境を構築するため、環境差異が生じにくい。
複数言語・複数ツールの統合管理
Node.js、Python、Rust、Go...プロジェクトごとに異なる言語スタックを使う場合でも、Nixで統一的に管理できる。asdfやmiseのようなバージョンマネージャを言語ごとに使い分ける必要がない。
セキュリティ・コンプライアンス
「このシステムには何がインストールされているか」を正確に追跡できる。ハッシュベースの管理により、意図しない変更が混入していないことを検証できる。金融機関などセキュリティ要件が厳しい環境で採用されている理由の一つ。
過去の環境の再現
「3年前のプロジェクトを、当時と同じ環境で動かしたい」という要求に応えられる。flake.lockがあれば、当時のNixpkgsのリビジョンから当時のパッケージバージョンを再現できる。
Nix vs 他のアプローチ
vs Homebrew / apt

| 観点 | Homebrew / apt | Nix |
|---|---|---|
| ストレージモデル | ミュータブル(上書き) | イミュータブル(追加のみ) |
| 複数バージョン | 困難 | 自然にサポート |
| ロールバック | 困難 | 容易 |
| 再現性 | 保証なし | 保証あり |
| 学習コスト | 低 | 高 |
Homebrewは「手軽にパッケージをインストールしたい」という用途には最適だ。しかし「チーム全員で同じ環境を使いたい」「1年後に同じ環境を再現したい」という要求には応えにくい。
vs Docker

NixとDockerは競合ではなく、補完関係にある。
| 観点 | Docker | Nix |
|---|---|---|
| 再現性の対象 | ランタイム環境 | ビルドプロセス |
| 決定論性 | ビルド時のネットワーク等で変動 | 同じ入力 = 同じ出力 |
| 主な用途 | デプロイ、実行環境の隔離 | 開発環境、ビルド環境 |
| 組み合わせ | NixでDockerイメージをビルド可能 | - |
DockerfileのRUN apt-get update && apt-get install -y python3は、実行するタイミングによって異なるバージョンのPythonがインストールされうる。Nixでビルドしたイメージなら、常に同じバージョンが入る。
実際、「NixでDockerイメージをビルドする」という併用パターンは広く使われている。
vs asdf / mise
asdfやmiseは「言語ごとのバージョン管理」を行うツールだ。.tool-versionsファイルでNode.js 20、Python 3.11といったバージョンを指定する。
Nixはより広いスコープを持つ。言語ランタイムだけでなく、データベース、CLIツール、システムライブラリまで同じ仕組みで管理できる。ただし、その分学習コストも高い。
「Node.jsのバージョンだけ揃えたい」ならasdf/miseで十分かもしれない。「開発に必要なすべてのツールを宣言的に管理したい」ならNixが向いている。
Nixの代償:学習コストの実態
Nixを使うかどうかの判断で最も重要なのは、学習コストとの見合いだ。
急峻な学習曲線
Nixの学習曲線は「山」と表現されることが多い。
- Nix言語の習得 - 関数型言語に馴染みがないと、構文や考え方に戸惑う
- 独自概念の理解 - derivation、store、overlay、flake...Nix固有の概念が多い
- ドキュメントの難しさ - 改善されてきているが、まだ初心者に優しいとは言い難い
- エラーメッセージ - 何が問題なのかわかりにくいことがある
日常の摩擦
Nixを使いこなせるようになっても、日常的な摩擦は残る。
- すべての変更が設定ファイル経由 - 「ちょっとこのツールを試したい」だけでも、Nix設定を書く必要がある
- ビルド時間 - キャッシュがない場合、ビルドに時間がかかることがある
- ストレージ使用量 - イミュータブルな設計上、古いバージョンが残り続ける(ガベージコレクションは可能)
「すべてをNixで」vs「部分的に導入」
Nixを全面採用するか、部分的に使うかは重要な選択だ。
全面採用(NixOS + Home-Manager)
- 再現性の恩恵を最大限受けられる
- 学習コスト・運用コストも最大
- 「Nixでできないこと」に直面すると困る
部分的導入(既存OS + Nix開発環境)
- 特定プロジェクトの開発環境だけNixで管理
- Homebrewなど既存のツールと共存
- 段階的に適用範囲を広げられる
多くの場合、部分的導入から始めて、価値を感じたら範囲を広げていくのが現実的だ。
Nixを学ぶべき人、学ばなくてよい人
学ぶ価値が高い人
- 「works on my machine」問題に頻繁に遭遇する - チーム開発や複数マシン間での環境差異に悩んでいる
- 長期的なプロジェクトを持っている - 数年後に同じ環境を再現する必要がある
- OSを含めた環境全体をコード化したい - Infrastructure as Codeの延長線上
- 関数型プログラミングに抵抗がない - Haskell、Elm、OCaml等の経験があると学習が楽
無理に学ぶ必要がない人
- 個人開発がメインで環境差異に困っていない - オーバーキルになりやすい
- 短期プロジェクトが多い - 学習コストを回収する前にプロジェクトが終わる
- チームにNix経験者がいない - 一人で導入・運用するのは負担が大きい
- すぐに結果が欲しい - Nixの恩恵は長期的に現れる
まとめ
Nixは「パッケージをイミュータブルに、純粋関数的に管理する」という思想に基づいたエコシステムだ。
従来のパッケージ管理の問題(依存関係地獄、環境差異、壊れるアップグレード)を、ハッシュベースのストレージと宣言的プログラミングで解決しようとしている。
学習コストは高いが、一度習得すれば「環境は解決済みの問題」になる。Shopify、Replit、Andurilといった企業が本番環境で採用していることからも、その価値は実証されている。
すべての人にNixが必要なわけではない。しかし「再現性」と「宣言的管理」に価値を感じるなら、投資する価値のあるエコシステムだと思う。
次のステップ
Nixに興味を持ったら、以下のリソースから始めるのがおすすめだ。
- Nix公式サイト - How Nix Works - 公式の概念解説
- Zero to Nix - Determinate Systems による入門ガイド
- NixOS & Flakes Book - 非公式だが評判の良い入門書
- Home-Manager Manual - dotfiles管理から始めたい人向け
参考リンク
- Nix公式サイト
- Nixpkgs
- nix-community/awesome-nix
- Nix vs Docker比較 - DevZero
- Three Years of Nix and NixOS - Pierre Zemb
抽出された概念
- 純粋関数型パッケージ管理 - パッケージを純粋関数の戻り値として扱う設計思想(新規作成)
- 依存関係地獄 - 複数のパッケージが同一ライブラリの異なるバージョンを要求し共存できなくなる問題(既存)
- Content-Addressable Storage - 入力ハッシュからパスを決定するNix Storeの仕組み(既存)
- イミュータビリティ - 追加のみでデータを変更しないという性質(既存)
- 再現性 - 同じ入力から常に同じ結果が得られること(既存)
- 宣言的プログラミング - 最終状態を宣言する設計パラダイム(既存)