Nixで開発環境を構築する(nix-shell / flakes 実践)
Nixで再現性の高い開発環境を構築する方法を、nix-shellやflakesの使い方、Node.js環境の例まで実例を交えてわかりやすく解説します。
🎯 この記事で学べること
- 1なぜNixで開発環境を作ると「壊れない」のかを理解できます
- 2nix-shellで一時的な開発環境をサッと立ち上げる方法がわかります
- 3shell.nixでチーム全員が同じ環境を再現する方法を学べます
- 4flakesによるモダンで完全に固定された環境管理を理解できます
- 5Node.js環境の具体例とDockerとの使い分けを把握できます
読了時間: 約11分

新しいPCに開発環境を入れ直したら、またバージョンがズレて動かない... Node.jsもPythonも、READMEの手順どおりやったのに。

あるあるだね。それ、Nixで開発環境を作ると かなり解決できるよ。プロジェクトに設定ファイルを1個置くだけで、 誰のPCでも同じ環境が立ち上がるんだ。

え、1個のファイルで?でもNixって難しそうな イメージあるんだけど...

OS全部をNixで管理しようとすると大変だけど、 「開発環境だけ」ならテンプレをコピーして少し直すだけ。 今日はnix-shellとflakesの2つの作り方を、Node.jsの例で見ていこう!
なぜNixで開発環境を作るのか
「自分のPCでは動くのに、他の人の環境では動かない」——チーム開発で何度も繰り返されるこの問題の根本原因は、環境の再現性が保証されていないことにある。
brew install nodeやapt install nodejsは「最新版を入れろ」という命令だ。先週インストールした人と今日インストールした人で、入るバージョンが違う可能性がある。READMEに「Node.js 18が必要」と書いてあっても、実際に18が入っている保証はどこにもない。
Nixはこの問題を、宣言型・純粋関数型の発想で解決する。詳しい設計思想は別記事「Nixとは?宣言型パッケージ管理で開発環境の「壊れた」をなくす方法」で解説しているが、ここで押さえておきたいのは次の3点だ。
- バージョンが共存できる: Node.js 18と20を同じマシンに入れても衝突しない。プロジェクトごとに違うバージョンを使い分けられる。
- 入力が同じなら結果も同じ: 設定ファイルが同じなら、いつ・どこで実行してもまったく同じ環境ができる。
- システムを汚さない: 開発環境を作っても、グローバルな
/usr/binを書き換えたりしない。シェルを抜ければ元通り。
つまりNixで開発環境を構築するということは、「環境の作り方」をコードとしてGitに残すということだ。新しいメンバーが入っても、PCを買い替えても、コマンド一発で同じ環境が手に入る。
この記事はNix本体がインストール済みであることを前提にしています。まだの場合は、Linux・macOSともに公式インストーラーのワンコマンドで導入できます。導入手順はNix公式ドキュメント(nixos.org)を参照してください。
nix-shellで一時的な環境を作る
まず一番手軽な使い方から。nix-shellを使うと、特定のツールが入った一時的なシェル環境をその場で立ち上げられる。システムには何もインストールされない。
たとえば「いまだけNode.jsを使いたい」場合。
# Node.jsが入った一時シェルに入る
nix-shell -p nodejs_18
# このシェルの中ではnodeが使える
node --version
# exitすると、元のシェルに戻る(nodeは消える)
exit
-p(package)オプションで、必要なパッケージを並べるだけだ。複数指定もできる。
# Node.js・jq・curlをまとめて使える一時環境
nix-shell -p nodejs_18 jq curl
シェルを抜けた瞬間、これらのツールは見えなくなる。グローバル環境を汚さずに「ちょっと試す」ができるのがnix-shell -pの良さだ。
似た用途のコマンドにnix runもあります。nix run nixpkgs#cowsay -- "Hello"のように、シェルに入らずワンショットでツールを実行できます。「一度だけ実行したい」ならnix run、「しばらくそのツールを触りたい」ならnix-shell -pが便利です。
ただしnix-shell -pは、その場限りの使い捨て向きだ。プロジェクトの開発環境として毎回同じツール群を呼び出すなら、次に紹介するshell.nixを使う方がはるかに管理しやすい。
shell.nixで再現可能な環境を定義する
プロジェクトに必要なツールをファイルに書き出すのがshell.nixだ。プロジェクトのルートに置き、nix-shellと打つだけで、そのプロジェクト専用の環境が立ち上がる。
# shell.nix
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
buildInputs = with pkgs; [
nodejs_18
python311
git
jq
];
shellHook = ''
echo "開発環境が準備できました"
echo "Node.js: $(node --version)"
'';
}
# プロジェクトディレクトリで実行するだけ
nix-shell
これでNode.js 18、Python 3.11、Git、jqが揃ったシェルが起動する。buildInputsに並べたものが、その環境で使えるツールだ。shellHookはシェルに入った瞬間に実行されるスクリプトで、環境変数の設定や起動メッセージの表示に使える。
ポイントは、このshell.nixをGitリポジトリにコミットすることだ。チームの誰もがgit cloneしてnix-shellと打つだけで、まったく同じツールが揃った環境を手に入れられる。「README手順を1個ずつ実行する」必要はもうない。
direnvで自動化する
毎回nix-shellと打つのが面倒なら、direnvと組み合わせると快適になる。プロジェクトディレクトリに入るだけで、自動的にNix環境が有効になる仕組みだ。
# .envrcを作成して許可する
echo "use nix" > .envrc
direnv allow
これで対象ディレクトリにcdするたびに環境が自動ロードされ、ディレクトリを出ると元の環境に戻る。shell.nixと.envrcをセットでコミットしておけば、クローンしてdirenv allowするだけで開発を始められる。
nix-shell + direnvは、Nixユーザーの間では定番のワークフローです。プロジェクトごとに異なるNode.jsやPythonのバージョンを使い分けたいときに特に威力を発揮します。
flakesによる現代的な環境管理
shell.nixには一つ弱点がある。冒頭のimport <nixpkgs> {}が指すnixpkgsのバージョンが環境によって違うかもしれない点だ。Aさんのマシンと、半年後に環境を作るBさんのマシンで、<nixpkgs>が別バージョンを指していれば、得られるNode.jsの細かいバージョンがズレる可能性がある。
これを解決するのが**Nix Flakes(フレイク)**だ。
Flakesは、依存しているnixpkgsのバージョンをflake.lockファイルで正確に固定する。npmのpackage-lock.jsonやRustのCargo.lockと同じ発想だと考えればわかりやすい。一度lockファイルができれば、いつ・どこで実行してもまったく同じ環境が再現される。
flake.nixの例
# flake.nix
{
description = "My project development environment";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = nixpkgs.legacyPackages.${system};
in
{
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [
nodejs_18
python311
git
];
};
}
);
}
inputsで「どのnixpkgsを使うか」をGitのブランチやタグで指定し、devShells.defaultで開発環境の中身を定義している。flake-utilsを使っているのは、Linux(x86_64)でもmacOS(Apple Silicon)でも同じ定義が動くようにするためだ。
# Flakeベースの開発環境に入る
nix develop
# 初回実行時にflake.lockが自動生成される
git add flake.nix flake.lock
shell.nixではnix-shellだったが、Flakesではnix developで環境に入る。重要なのは生成されたflake.lockを必ずGitにコミットすることだ。このファイルが依存関係の正確なバージョン(Gitのコミットハッシュ)を記録しており、再現性の要になる。
Flakesを有効にする
Flakesは便利だが、2026年現在もNixでは「実験的機能」という位置づけのため、明示的に有効化する必要がある。
# ~/.config/nix/nix.conf に追記する
echo "experimental-features = nix-command flakes" >> ~/.config/nix/nix.conf
「実験的機能」とはいえ、Flakesは事実上のデファクトスタンダードになっています。新しくNixプロジェクトを始めるなら、最初からFlakesで構成しておくのがおすすめです。
shell.nix と flakes の使い分け
2つの方法を整理しておこう。
| 比較項目 | shell.nix(nix-shell) | flake.nix(nix develop) |
|---|---|---|
| 環境に入るコマンド | nix-shell | nix develop |
| nixpkgsのバージョン固定 | 弱い(<nixpkgs>に依存) | 強い(flake.lockで固定) |
| 必要な設定 | なし(すぐ使える) | experimental-featuresの有効化 |
| 学習コスト | 低め | やや高め |
| 再現性 | 中(環境により差が出うる) | 高(完全に固定) |
| 向いている場面 | 個人・小規模・お試し | チーム・長期・厳密な再現 |
ざっくり言えば、まずshell.nixで試し、本格的にチームで使うならflakesへという流れが自然だ。どちらもpkgs.mkShellとbuildInputsという同じ部品を使うので、shell.nixに慣れていればFlakesへの移行は難しくない。
迷ったら最初はshell.nixで十分です。プロジェクトが育ってチームの人数が増え、「環境の細かいズレ」が問題になり始めたタイミングでflakesに移行すると、無理なくステップアップできます。
Node.js開発環境の実例
具体的にNode.jsプロジェクトの環境を組んでみよう。よくあるのは「特定のNode.jsバージョン + よく使うCLIツール」の組み合わせだ。
# shell.nix(Node.jsプロジェクト向け)
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
buildInputs = with pkgs; [
nodejs_18
nodePackages.pnpm
nodePackages.typescript
git
];
shellHook = ''
echo "Node.js: $(node --version)"
echo "pnpm: $(pnpm --version)"
'';
}
このshell.nixがあれば、nix-shellに入った時点でNode.js 18、pnpm、TypeScript、Gitがすべて使える状態になる。チームメンバーがNode.jsを手動でインストールする必要はない。
# 環境に入る
nix-shell
# あとは普段どおり
pnpm install
pnpm run dev
ここで一つ注意点がある。node_modulesの中身はNixが管理しないということだ。Nixが揃えるのは「Node.js本体やpnpmといったツール」であり、pnpm installで入れるプロジェクト依存パッケージは、これまでどおりpnpm(やnpm)が管理する。Nixは「土台となるツールチェーンの再現性」を担保する役割だと考えるとわかりやすい。
別バージョンが必要になったら、buildInputsのnodejs_18をnodejs_20に書き換えるだけでいい。
buildInputs = with pkgs; [
nodejs_20 # 18から20に変えるだけ
nodePackages.pnpm
];
書き換えてもう一度nix-shellに入れば、今度はNode.js 20の環境が立ち上がる。グローバルなNode.jsを入れ替える必要も、バージョン管理ツールを別途用意する必要もない。プロジェクトごとに違うバージョンを使い分けるのが、設定ファイル1行の変更で済む。
利用できるパッケージ名(nodejs_18、python311など)や、特定バージョンの提供状況はnixpkgsの更新によって変わります。使いたいパッケージがあるかどうかはnix search nixpkgs nodejsのようにして確認するか、search.nixos.orgで検索してください。本記事のバージョン番号は一例です。
Dockerとの使い分け
「環境を固定するならDockerでいいのでは?」とよく聞かれる。結論から言うと、両者は競合ではなく補完関係だ。
| 観点 | Nix(nix-shell / flakes) | Docker |
|---|---|---|
| 主な対象 | 開発環境のツールチェーン | アプリの実行環境まるごと |
| 分離のレベル | ホスト上で動く(軽量) | コンテナで隔離 |
| ホストとの親和性 | 高い(ローカルのファイルをそのまま編集) | ボリュームマウントが必要 |
| 本番環境との一致 | ツール単位 | 環境まるごと一致させやすい |
| 起動の速さ | 速い(ネイティブ実行) | イメージ次第 |
使い分けの目安はこうだ。
- 手元の開発作業をサクサク進めたいなら、ホスト上でネイティブに動くNixが軽快だ。エディタやデバッガとの相性もよい。
- 本番と同じOS・ミドルウェア構成で動かしたい、あるいはPostgreSQLなどのミドルウェアごと隔離したいなら、Dockerが向く。
そして両者は組み合わせられる。NixでDockerイメージをビルドするという使い方も人気で、「開発はNix、配布はDockerイメージ」というワークフローも成り立つ。Dockerの代替や軽量化を検討しているなら、「Docker Desktopの代替ツール」もあわせて参考にしてほしい。
「ローカルの開発環境はNixで軽く、本番デプロイはコンテナで」という分業は、多くのチームで現実的な落としどころになっています。どちらか一方に絞る必要はありません。
よくある質問(FAQ)
nix-shellとnix developの違いは何ですか?

どちらも開発環境のシェルに入るコマンドですが、対象が違います。nix-shellは伝統的なshell.nixを読み込み、nix developはFlakes(flake.nix)を読み込みます。nix developはflake.lockで依存バージョンを厳密に固定できるため、再現性がより高いのが特長です。まずはnix-shellで試し、チームで厳密に揃えたくなったらnix developへ移行するのがおすすめです。
shell.nixとflake.nixはどちらを使うべきですか?

個人やお試しならshell.nixで十分です。設定なしですぐ使えて学習コストも低めです。一方、チームで長期的に開発し、環境のわずかなズレも許したくない場合はflakesが向きます。flake.lockによって誰の環境でも完全に同じものが再現されるためです。どちらもpkgs.mkShellという同じ部品を使うので、移行はスムーズです。
Nixで作った環境でnpm installは普通に使えますか?

使えます。Nixが揃えるのはNode.js本体やpnpm・npmといった「ツールチェーン」で、npm installやpnpm installで入るプロジェクト依存パッケージはこれまでどおり各ツールが管理します。Nixは土台のツールの再現性を担保し、node_modulesの管理は従来どおり、という役割分担になります。
Node.jsのバージョンを切り替えるにはどうすればいいですか?

shell.nixやflake.nixのbuildInputsに書いたパッケージ名を変えるだけです。たとえばnodejs_18をnodejs_20に書き換えて、もう一度nix-shell(またはnix develop)に入り直せば、新しいバージョンの環境が立ち上がります。グローバルなNode.jsを入れ替えたり、別途バージョン管理ツールを用意したりする必要はありません。
Dockerがあれば、Nixで開発環境を作る必要はないのでは?

両者は補完関係です。Dockerはアプリの実行環境まるごとを隔離するのが得意で、Nixはホスト上で動く軽量なツールチェーン管理が得意です。手元の開発を軽快に進めたいならNix、本番と同じ構成やミドルウェアごと隔離したいならDocker、という使い分けが現実的です。NixでDockerイメージをビルドするなど、両方を組み合わせる使い方も人気です。
まとめ:まずはshell.nixを1つ置いてみる
Nixで開発環境を構築する流れを振り返っておこう。
- nix-shell -p で、その場限りのツールをサッと使える。「ちょっと試す」用途に最適。
- shell.nix に必要なツールを書いてコミットすれば、チーム全員が
nix-shell一発で同じ環境を再現できる。 - direnv と組み合わせれば、ディレクトリに入るだけで環境が自動で有効になる。
- flakes(flake.nix) なら
flake.lockで依存を完全に固定でき、最も再現性が高い。 - Node.jsのような環境も、バージョン変更は設定ファイル1行の書き換えで済む。
- Dockerとは競合せず、開発はNix・配布はDockerのように補完し合える。
最初の一歩として難しいことは要らない。手元のプロジェクトにshell.nixを1つ置き、必要なツールを並べてnix-shellと打つ——それだけで「自分のPCでは動くのに」問題の多くから解放される。
いきなりflakesやNixOSを目指す必要はありません。まずはshell.nixで再現性の手応えをつかみ、気に入ったらflakesへステップアップしましょう。Nixの設計思想そのものをもっと知りたい人は「Nixとは?宣言型パッケージ管理」の記事もあわせてどうぞ。
おすすめコース
関連記事
Docker Desktop代替ツール比較 - 無料で使えるコンテナ環境5選【2026年最新】
Docker Desktopの代替ツールを徹底比較。Podman Desktop、Rancher Desktop、OrbStack、Lima、Colima等の無料コンテナツールの特徴・メリット・デメリットをWindows/Mac/Linux対応状況と合わせて紹介します。
Nixとは?宣言型パッケージ管理で開発環境の「壊れた」をなくす方法【2026年最新】
Nixパッケージマネージャーの特徴と仕組みを初心者向けに解説。再現可能な開発環境の構築、従来のパッケージ管理との違い、nix-shellやFlakesの使い方を紹介します。
シェルスクリプトの第一歩
Bashシェルスクリプトの基本を学び、日常的な作業を自動化する方法を実例を交えて詳しく解説します。


