2026-06-13

設定ファイルはNixで管理せず、シンボリックリンクに落ち着いた話

やりたいこと

前回 、NixでCLIツールを管理できるようにしました。ワンコマンドで必要なツールが揃うのが快適だったので、せっかくNixを入れたなら、.zshrc や neovim などの設定ファイル(dotfiles)もNixで管理できないか試してみることにしました。

ただ、結論から言うと 設定ファイルはNixで管理せず、これまで通りシンボリックリンクで管理する ことに落ち着きました。

この記事は、実際にNix管理を試してみて、なぜ最終的にシンボリックリンクに戻したのか、という試行錯誤の記録です。

設定ファイルの置き方(mkOutOfStoreSymlink)

home-managerでは、設定ファイルも配置できます。やり方は大きく2つあって、挙動が違います。

書き方挙動
source = ./somefileファイルをNixストアにコピーしてから配置する。編集するたびに switch が必要
source = mkOutOfStoreSymlink "..."dotfilesの実体に直接シンボリックリンクを張る。編集したら即反映、switch 不要

設定ファイルは普段から直接編集するので、switch なしで編集が反映される mkOutOfStoreSymlink(out of store = ストアの外の実体を直接指す)を選びました。home.nix にはこう書きます。

  • xdg.configFile."nvim" … リンク先(~/.config/nvim)を指定する
  • mkOutOfStoreSymlink "..." … リンク元(dotfilesの実体)を指定する

この時点では、これでNixでも ln と同じようにリンクが張れる、と思っていました。

nvimの設定をNix管理にしてみる

いきなり全部移すのは不安だったので、まずは neovim の設定だけをNix管理に移してみました。

これまでは、セットアップスクリプトの中で ln コマンドを使って手動でリンクを張っていました。

これを前述の home.nix の書き方に置き換えて switch します。

ここで一つ注意点がありました。~/.config/nvim にはすでに手動で張ったシンボリックリンクが残っているため、このまま switch すると「home-managerが管理していないファイルがある」とエラーになります。なので、先に古いリンクを外してから switch する必要がありました(リンクを外しても、実体はdotfiles側に残るので消えません)。

switch 後、リンクのチェーンを readlink -f で辿ってみると、ちゃんと最終的にdotfilesリポジトリの実体に到達していました。lazy-lock.json(lazy.nvimが書き込むロックファイル)も書き込み可能で、mkOutOfStoreSymlink が狙い通り動いていることが確認できました。

neovimを起動しても設定の読み込みエラーは出ず、移行自体は問題なく完了しました。

……のですが、移行を進めるうちに「これ、わざわざNixでやる意味あるんだっけ?」と思い始めました。引っかかったのは、どちらも「パスの書き方」に関する2点でした。

引っかかった2つの点

ユーザー名をNix側に持たせないといけない

dotfilesは複数のマシンで使い回したいのですが、マシンによってユーザー名(=ホームディレクトリのパス)が違います。Nixでこれを扱うには、flake.nix でユーザー名を変数として注入し、home.nix 側で ${config.home.homeDirectory} のように組み立てることになります。

設定ファイルを置きたいだけなのに、マシンごとの差分を吸収する仕組みをNix側に足すことになり、だんだん大げさに感じてきました。

絶対パスを自分で組み立てないといけない

mkOutOfStoreSymlink に渡すのは絶対パスです。なので前述の home.nix のように、let でリンク元のパスを最初から組み立てておく必要がありました。

一方、これまでの ln はこうでした。

$(pwd)$HOME も実行時に解決されるので、絶対パスを自分でハードコードする意識がいりません。symlinkを張るときの「今いる場所から相対的に張る」感覚に近く、こっちの方が素直でした。

結局やりたかったのは「dotfilesの実体にリンクを張る」だけで、それなら ln 一行で済んでいたことを、Nixの記法に置き換えただけ。ユーザー名の注入と絶対パスの組み立てという手間が増えただけで、見合うものが得られていないと感じて、設定ファイルのNix管理はやめることにしました。

chezmoiは?

前述のユーザー名問題をきれいに解決できそうだったのが chezmoi です。テンプレートでマシンごとに設定の中身を変えられて、秘密情報も暗号化できる。ユーザー名も {{ .chezmoi.username }} という組み込み変数で実行環境から自動取得できるので、Nixのように flake.nix でユーザー名を注入する仕組みは要りません。

これは良さそうだと思ったのですが、結局 chezmoi も採用しませんでした。理由は、ファイルを編集しても即反映されないこと。

chezmoiはシンボリックリンクではなく、ソースから実ファイルを生成してコピーする方式です。

ソースと実ファイルが別物なので、反映には必ずコマンドを挟まないといけません。しかも両方向で手間がかかります。

編集する場所反映に必要なコマンド
ソースを編集chezmoi apply(ホームへ書き出す)
ホーム側を直接編集chezmoi re-add(ソースへ取り込む)

自分は ~/.config/nvim/ を直接編集するので、編集のたびに re-add を忘れず実行しないといけません(忘れると次の apply で上書きされて消える)。設定をいじってすぐ試せなくなる。これがどうしても合いませんでした。

シンボリックリンクなら実体は1つなので、編集はそのまま反映されます。username問題は解決できても、即反映されないという一点が大きく、chezmoiは見送りました。

結論

いろいろ試した結果、こういう役割分担に落ち着きました。

  • CLIツール(packages) → Nixで管理する。宣言的に書けて、バージョン固定も複数PC対応もできる。Nixが明確に強い領域
  • 設定ファイル(dotfiles) → これまで通りシンボリックリンクで管理する(今は ln

設定ファイルに関しては、mkOutOfStoreSymlink で絶対パスを宣言的に組み立てるより、$HOME を実行時に解決してくれる ln の方が素直でした。直接編集してすぐ反映される手軽さも、そのまま残ります。

試しにNix管理へ移した neovim の設定は元に戻し、home.nix の変更も取り消しました。遠回りでした。それでも、設定ファイルはNixに載せない、とはっきり決められたのは収穫です。設定を毎日直接いじるなら、迷わず ln でいい。Nixはツールの管理に集中させる。これが今の自分の結論です。

Thanks for the visit Nozo Blog