はじめに
はじめまして。社内唯一のVimmer西川です。
最近、個人開発で Nix を使い始めて、開発環境をコードで管理できる体験に感動しています。
私は個人の OSS 開発で Rust / TypeScript / JavaScript / Python などを使っており、Cargo クレートや npm パッケージを作ることがあります。複数の言語やツールを扱っていると、Node、Rust、Python、CLI ツール、Vim 周りの設定などが少しずつローカル環境に積み重なっていきます。
さらに、昔使っていた MacBook Pro と M4 Mac mini を併用していることもあり、複数マシン間で環境を揃える難しさも感じていました。
今振り返ると、M4 Mac mini を購入したタイミングで、NixOS 的な「環境全体を宣言的に管理する考え方」をもっと早く取り入れていればよかったと思っています。
一方で、個人開発で便利だったものを、そのまま実務プロジェクトに持ち込めるとは限りません。
そこで今回は、Docker + Docker Compose をベースにした既存プロジェクトに対して、Nix を活かすならどこまで現実的なのかを整理してみました。
今回のテーマは、
Nixを導入するかどうかではなく、Dockerベースの実務開発でどこまで活かせそうか
です。
これまでの開発で感じていた課題
※ この章は、これまで関わった複数プロジェクトでの経験をまとめたものです。本プロジェクト固有の問題ではありません。
これまでの開発では、以下のような環境差分に悩むことがありました。
- Mac / Windows で Docker ビルドが通らない
- Apple Silicon と x86 の差異
- Windows 環境で Docker 周りが不安定になる
- WSL2 上の Docker と Docker Desktop の構成差
- ホスト側パッケージの差異
- Node / Composer / npm / pnpm / cargo などのバージョン差
- README 通りに進めても環境によって結果が変わる
ここから感じたのは、
Dockerがあっても、ホスト環境の差分は残る
ということです。
Docker はアプリケーションの実行環境を揃えるには強力ですが、Docker を起動する前のホスト側ツールや OS 設定までは完全には管理してくれません。
AI開発時代に環境をコード化する意味
最近は AI を使ってコードを書く機会も増えています。
AI は構文やライブラリの使い方をかなり補助してくれます。一方で、プロジェクトが前提としている実行環境やツールチェインが曖昧だと、生成されたコードを動かす段階で詰まることがあります。
たとえば、以下のような情報です。
- Node / Rust / Python / Go のバージョン
- npm / pnpm / Composer / cargo の使い分け
- 必要な CLI ツール
- ローカル証明書や hosts 設定
こうした情報が README や個人の記憶に依存していると、人間にも AI にも扱いづらい状態になります。
その点で、Nix の価値は単なるパッケージ管理ではなく、
開発環境そのものをプロジェクトの一部として管理できること
にあると感じています。
本プロジェクトの現状
本プロジェクトでは、Docker + Docker Compose により、以下の実行環境がコンテナ化されています。
- MySQL
- NestJS
- React + Vite
- nginx
そのため、アプリケーションの実行環境は基本的に再現可能です。
一方で、セットアップ手順やコードを見ると、Docker の外側に以下の依存が残っていました。
| 依存 | 用途 |
|---|---|
| Docker / Docker Compose | コンテナ起動 |
| mkcert | ローカル証明書生成 |
| bash | スクリプト実行 |
| hosts編集 | ドメイン解決 |
| loopback設定 | ローカルIPバインド |
| git | clone |
※ 本プロジェクトでは Node.js はコンテナ内で完結しており、ホスト側の Node バージョン差異は基本的に問題になりません。
つまり、本プロジェクトでの論点は Docker を置き換えることではなく、
Dockerの外側に残っているホスト依存を、Nixでどこまで減らせるか
です。
Dockerで解決できていない部分
Docker により実行環境は統一されていますが、ローカル開発では以下のようなホスト依存の操作が残ります。
- hosts ファイルの編集
- mkcert による証明書生成と OS ストアへの登録
- loopback 設定
.envの作成- ポート競合の確認
- Docker Desktop / WSL2 などのローカル構成差
つまり、
Dockerは実行環境を揃えるが、OSレイヤーの操作までは揃えない
という整理になります。
これは Docker の欠点というより、責務の違いです。
Nixでできること
Nix を使うと、開発に必要なツールを flake.nix に宣言できます。
本プロジェクトで直接効果がありそうなのは、以下のようなホスト側 CLI の固定です。
- mkcert
- curl
- bash
- MySQL 接続確認用ツール
- その他、開発補助 CLI
一方で、別プロジェクトのように Node や Composer をホスト側で使う構成では、Nix の効果はさらに大きくなります。
たとえば、以下のような差分です。
- Node バージョン差異
- Composer の依存解決差異
- Rust / Python / Go など複数言語のツールチェイン差異
- npm / pnpm / cargo などの CLI 差異
こうした問題は、Nix によって減らせる可能性があります。
個人開発では、nix develop でプロジェクトごとに必要なツールを切り替えられる点が特に便利だと感じています。グローバル環境を汚さず、プロジェクト単位で開発環境を持てるのは大きなメリットです。
Nixでも解決できないこと
一方で、Nix を入れても解決できないこともあります。
- hosts 編集の権限問題
- OS の証明書ストアへの CA 登録
- Docker Desktop / WSL2 の構成差
- OS ごとのネットワーク設定
.envのシークレット値管理
.env.example から .env を生成する補助はできますが、シークレット値や各自のローカル設定値をどう管理するかは、Nix だけで完結する話ではありません。
また、Windows で Nix を利用する場合、現実的には WSL2 上での運用が前提になりやすいです。そのため、WSL2 と Docker Desktop の構成に起因する問題は、Nix を導入してもそのまま残る可能性があります。
つまり、
Nixはホスト側ツールチェインの再現性を高めるが、OS設定まですべて抽象化するものではない
という理解が必要です。
設計としての落としどころ
Dockerベースの実務プロジェクトにNixを当てはめるなら、以下のような役割分担が現実的だと考えました。
上記を整理すると、Docker・Nix・OS設定の役割は以下のように分けられます。
※ ここに図を差し込む想定です。
| 領域 | 管理方法 |
|---|---|
| アプリ実行環境 | Docker |
| DB / nginx など | Docker |
| 開発ツール | Nix |
| OS設定 | 手動 |
もし小さく試すなら、まずは以下のようなツールをNix管理の候補にできそうです。
- mkcert
- curl / bash などの CLI
- 必要に応じた DB 接続確認用ツール
一方で、Docker CLI や Compose は Docker Desktop / Docker Engine 側に寄せ、Nix の管理対象からは外します。
重要なのは、
NixはDockerの代替ではなく、Dockerの外側を補う選択肢
ということです。
Docker がすでに担っている領域まで Nix で置き換える必要はありません。Docker の外側に残っているホストツール管理を Nix で補う方が、導入コストと効果のバランスが良いと考えています。
flake.nixの最小例
以下は、開発ツールを Nix で管理するための最小例です。
{
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
outputs = { self, nixpkgs, ... }: {
devShells.x86_64-linux.default =
let
pkgs = nixpkgs.legacyPackages.x86_64-linux;
in
pkgs.mkShell {
packages = [
pkgs.mkcert
pkgs.curl
pkgs.bash
# DB接続確認用ツールは、利用するnixpkgsに応じて別途追加
];
};
};
}
※ この例は x86_64-linux 前提です。
※ Mac で使う場合は aarch64-darwin / x86_64-darwin の追加、または flake-utils などを使った複数 platform 対応を検討します。
※ docker-compose は Compose v2 の扱いを考慮し、この例では Nix 管理対象から外しています。ただし、会社のプロジェクトでは最初から広げすぎず、まずは flake.nix による devShell から始めるのが現実的だと思います。
結論
今回整理してみて、Dockerベースの実務開発に対してNixを活かすなら、いきなり全面導入するよりも、ホスト側ツール管理から小さく試すのが現実的だと感じました。
Dockerは実行環境の再現性を担保してくれます。一方で、mkcert、curl、bash、DB接続確認用ツールなど、Dockerの外側にある開発補助ツールはホスト環境に依存しがちです。
Nixはその領域をコード化し、開発者間の差分を減らす手段になり得ます。
ただし、hosts編集、CA登録、Windows / WSL2 の構成差、.env のシークレット管理まではNixだけでは解決できません。
そのため、現時点では、
Dockerを置き換えるのではなく、Dockerの外側に残るホストツール管理をNixで補う
くらいの距離感が、実務導入の第一歩としてちょうどよさそうです。
おわりに
個人開発で Nix を使ってみて、環境を宣言的に管理できることには大きな可能性を感じています。
特に、複数マシンを使う場合や、Rust / TypeScript / Python / Go など複数言語を扱う場合、プロジェクトごとに環境を固定できるのは非常に便利です。
一方で、実務プロジェクトでは「便利だから全部入れる」ではなく、
どこに導入すると効果があり、どこから先は運用コストが高いのか
を見極める必要があります。
今回の結論は、Docker と Nix のどちらが優れているかではありません。
- Docker → 実行環境
- Nix → 開発ツール環境
- OS → 最後に残る依存レイヤー
このように役割を分けることで、無理なく開発環境の再現性を高められると感じました。