🫡

「ベストプラクティス」chezmoi × Nix で作るdotfiles 環境

に公開
2026/01/03

macOS は nix-darwin、Linux は flakey-profile、dotfiles は chezmoi。1つのリポジトリで「環境そのもの」を再現できるようにした構成の紹介です。

ソースコードは公開しています:https://github.com/signalridge/dotfiles
Star / Fork 歓迎です。質問や改善提案は Issue へどうぞ。


はじめに

開発者なら、こんな「つらさ」を経験したことはありませんか?

  • 新しい Mac に乗り換えるたびに、丸一日かけてツールを入れ直す
  • 会社PCと個人PCで設定が揃わず、便利なエイリアスや関数をつい忘れてしまう
  • .zshrc が肥大化して触るのが怖い(壊しそう)
  • 設定を同僚に共有したいのに、再現できない(「自分の環境では動く」)

私も同じでした。そこで以下の要件を課しました:

  1. 再現可能:別のマシンでも環境が「完全に同じ」になる
  2. プロファイル対応:仕事用 / 個人用を共存させ、差分を明示できる
  3. 復旧可能:設定破壊が起きても、すぐ前の版へ戻せる
  4. 共有可能:公開できる一方で、機密情報は安全に守る
  5. 保守可能:日常更新を標準手順に落とし込み、手作業に依存しない

最終的に chezmoi + Nix を軸にしました。今では新しいマシンでも1コマンドで環境を立ち上げられます:

sh -c "$(curl -fsLS get.chezmoi.io)" -- init --apply signalridge

構成の全体像

役割 ツール 担当範囲
ユーザー設定 chezmoi .zshrc、~/.config/* など
システム/パッケージ nix-darwin (macOS) / flakey-profile (Linux) CLI パッケージ、世代管理
GUI アプリ Homebrew VS Code、Ghostty、Raycast など
機密情報 chezmoi + age トークン、秘密鍵
.
├── .chezmoi.toml.tmpl    # 初回プロンプト/暗号化設定
├── .chezmoidata.yaml     # パッケージ/アプリ一覧(shared/work/private)
├── .chezmoiignore        # OS/環境に応じた除外設定
├── .chezmoiscripts/      # ブートストラップ/更新フック
├── nix-config/           # Nix flake
├── dot_custom/           # シェルロジック
└── private_dot_config/   # 各ツールの設定

Part 1: chezmoi 編

なぜ chezmoi を選んだのか

シンボリックリンク方式の限界

よくある dotfiles 管理は、設定を Git に入れてホームディレクトリへシンボリックリンクを張る方法です。ただ、これにはすぐ壁があります:

  • マシンごとの違いに弱い(会社機 / 個人機で破綻しがち)
  • テンプレート化しにくい(ホスト名・CPU・ヘッドレス運用などで切り替えたい)
  • 機密情報の扱いが難しい(API キーを入れると危険)
  • シンボリックリンクが脆い(パス変更・誤削除で壊れやすい)

Home Manager との比較

Nix エコシステムには Home Manager という強力なツールがあります。「Nix で統一するなら Home Manager でいいのでは?」という疑問は当然です。

観点 Home Manager chezmoi
学習コスト Nix 言語の習得が必須 シェルスクリプト + Go テンプレートで十分
導入の敷居 Nix がないと動かない 単体バイナリで即動く
既存設定の移行 Nix 式に書き直す必要あり そのまま chezmoi add で取り込める
デバッグ Nix の評価エラーは初心者に厳しい diff / apply のサイクルが直感的
暗号化 sops-nix 等の追加設定が必要 age 暗号化がビルトイン
非 Nix 環境 動かない どこでも動く

私が chezmoi を選んだ決め手:

  1. 段階的に始められる — 「まず .zshrc だけ」から拡張できる
  2. Nix がない環境でも動く — SSH 先、Codespaces、同僚のマシンでも OK
  3. 設定ファイルの「見た目」が変わらない — ほぼそのままの形で Git 管理
  4. 暗号化がシンプル — chezmoi add --encrypt で終わり

結論として、Nix は好きだけど dotfiles は chezmoi というスタンスに落ち着きました。


chezmoi の主要機能

1) テンプレート

.tmpl ファイルは apply 時にレンダリングされます:

[user]
    name = {{ .gitUsername }}
    email = {{ .gitEmail }}

差分は「手で直す」のではなく、データ駆動で生成します。

2) データの分層

パッケージとアプリの一覧を .chezmoidata.yaml に集約し、shared/work/private で分けています:

homebrew:
  casks:
    shared:
      - ghostty
      - nikitabobko/tap/aerospace
    work:
      - cursor
    private:
      - 1password

「2つのリポジトリ」ではなく、「1つのリポジトリ + 追跡可能な複数プロファイル」が得られます。

3) 初回プロンプト

.chezmoi.toml.tmpl で初回だけ必要な情報を聞いて保存します。以後は保存された値でレンダリングされるので、apply はノンストップで走ります:

  • work/private/headless のフラグ(headless は Codespaces/Remote を自動検出)
  • GitHub ユーザー名やメール
  • タイムゾーン(OS から自動検出、取れなければプロンプト)

4) 暗号化

age を使って機密ファイルを暗号化したままコミットできます。例えば:

private_dot_ssh/encrypted_private_config.tmpl.age

private_(権限)+ .tmpl(生成)+ .age(暗号化)の組み合わせです。1Password CLI (op) との連携も可能で、初回セットアップ時に鍵を自動取得します。

5) スクリプトフック

.chezmoiscripts/ でインストール手順をパイプライン化しています:

.chezmoiscripts/
├── run_onchange_before_00_install-nix.sh.tmpl
├── run_once_before_01_setup-encryption-key.sh
├── run_onchange_after_02_init.sh.tmpl
├── run_onchange_after_03_set_profiles.sh.tmpl
├── run_after_04_update_homebrew_packages.sh
├── run_onchange_after_05_mise-install.sh.tmpl
├── run_onchange_after_06_nix-index-db.sh.tmpl
└── run_onchange_after_07_install-paperlib.sh.tmpl

「新しいマシンを受け取ったら」が、手作業ではなく一本のパイプラインになります。

6) 柔軟な除外設定

.chezmoiignore はテンプレートとして書けるため、OS やプロファイルに応じてファイルを除外できます:

{{- if ne .chezmoi.os "darwin" }}
# Linux では macOS 専用の設定を除外
private_dot_config/aerospace/
private_dot_config/private_karabiner/
private_dot_config/ghostty/
{{- end }}

{{- if .headless }}
# ヘッドレス環境では GUI 関連を除外
private_dot_config/aerospace/
{{- end }}

1つのリポジトリで macOS / Linux / ヘッドレス環境すべてに対応できます。


Part 2: Nix 編

nix-darwin(macOS)

nix-darwin は NixOS の「宣言的システム設定」を macOS に持ち込むプロジェクトです。

命令的(従来のやり方):

brew install ripgrep bat fd
# 半年後:何を入れたか覚えていますか?バージョンは揃いますか?

宣言的(nix-darwin):

environment.systemPackages = with pkgs; [
  ripgrep
  bat
  fd
];

維持すべきは「一覧」だけ。システム状態はツールが計算して適用します。

nix-darwin の利点:

  1. 再現性 — flake.lock で依存バージョンを固定
  2. 原子的更新 — 切り替えは一括で行われる
  3. ロールバック — 失敗は世代を戻すだけで復旧
  4. macOS 設定も管理 — Dock / Finder / Trackpad などをコード化
  5. Homebrew も組み込める — GUI アプリを一元管理

flakey-profile(Linux)

Linux では OS の宣言的設定まで踏み込まず、「ユーザー環境(CLI ツール群)を flake で揃える」ことに寄せています。ホスト名ごとのプロファイルを切り替える形式です。

macOS は nix-darwin で "OS まで"、Linux は flakey-profile で "ユーザーまで"。どちらも flake.lock による固定とロールバックの恩恵を受けられます。

なぜ chezmoi と Nix の「合わせ技」なのか

置き換えではなく、役割分担です:

  • chezmoi — ユーザー設定(柔軟なテンプレート、暗号化)
  • Nix — パッケージと世代管理(再現性、ロールバック)

初期セットアップの流れ:

chezmoi init --apply
  ↓
00) Nix を導入
01) 復号鍵を用意
02) dotfiles をレンダリング
03) nix-darwin を適用(macOS)
04) Nix profile を切り替え
  ↓
Homebrew 更新 / mise / nix-index なども追随

Part 3: 実践編

モダン CLI ツールチェーン

従来 代替 重視する点
ls eza Git 連携、アイコン、ツリービュー
cat bat シンタックスハイライト、Git 差分表示
grep ripgrep 高速、.gitignore を尊重
find fd 直感的な文法
du dust 視覚的で分かりやすい
cd zoxide 利用履歴から高速ジャンプ
man tldr 必要な情報にすぐ届く

シェル環境

基本方針は「コマンドが存在するときだけ初期化」して、起動遅延と脆い依存を避けることです:

  • Starship — 統一されたプロンプト
  • Sheldon — 軽量な zsh プラグイン管理
  • Atuin — 強力な履歴検索(SQLite ベース)
  • direnv — ディレクトリ単位の環境変数
  • fzf — あらゆるものの曖昧検索

ワークフロー関数

dot_custom/functions.sh に用意している関数:

  • dev — ghq + fzf でプロジェクトへ高速ジャンプ
  • fgc/fgl/fga — ブランチ/コミット/ファイルを曖昧検索
  • fkill/port — プロセス kill、ポート調査
  • backup_dev_env — Brewfile / VS Code 拡張をエクスポート

AeroSpace

AeroSpace は macOS 向けの i3 ライクなタイル型ウィンドウマネージャです。設定例:

# ワークスペースをモニターに固定(3画面構成)
[workspace-to-monitor-force-assignment]
1 = 1  # モニター1: ワークスペース 1-3
4 = 2  # モニター2: ワークスペース 4-6
7 = 3  # モニター3: ワークスペース 7-9

[mode.main.binding]
alt-i = 'focus up'
alt-k = 'focus down'
alt-j = 'focus left'
alt-l = 'focus right'
alt-q = 'close'
alt-b = 'balance-sizes'
alt-shift-f = 'layout floating tiling'

連携するシェル関数も用意しています:

wsrun 5 code .    # ワークスペース5で VS Code を開く
ws 5              # ワークスペース5に切り替え
wsm 4             # 現在のウィンドウをワークスペース4に移動

AI 統合

aicommit は複数のプロバイダに対応しています:

aicommit           # デフォルト(Codex)
aicommit gemini    # Gemini を使用
aicommit --dry-run # 生成メッセージを確認

また、Claude Code をターミナルに統合して、リファクタリングやテスト作成に活用しています。

テーマ統一

よく使うツールのテーマ(Dracula)を揃えています。一貫した配色は長期利用の疲労を減らします。

メンテコマンド

高頻度の操作は Justfile に集約:

just darwin        # システム構成を再ビルド
just up            # flake inputs を更新
just full-upgrade  # 完全アップグレード
just gc            # 古い世代を掃除

始め方

この構成を使う

方法 1: GitHub から init スクリプトを直接実行(推奨)

curl -fsLS https://raw.githubusercontent.com/signalridge/dotfiles/main/init.sh | sh

方法 2: chezmoi をインストールして init

sh -c "$(curl -fsLS get.chezmoi.io)" -- init --apply signalridge

方法 3: クローンしてローカルで実行

git clone https://github.com/signalridge/dotfiles.git
cd dotfiles && ./init.sh

初回は Nix の導入、復号鍵のセットアップ、nix-darwin の switch まで自動で走ります。

以後の更新は just darwin / just full-upgrade に寄せると迷いにくいです。

ゼロから自分で作る

sh -c "$(curl -fsLS get.chezmoi.io)"
chezmoi init
chezmoi add ~/.zshrc
chezmoi add ~/.config/git/config --template
chezmoi add ~/.ssh/config --encrypt
chezmoi apply

chezmoi cd
git add -A && git commit -m "Initial commit"
git push -u origin main

段階的に足すおすすめの順序:

  1. .chezmoidata.yaml で shared/work/private の分層を作る
  2. 変わりやすい設定を .tmpl 化する
  3. age で機密ファイルを暗号化
  4. インストール手順を .chezmoiscripts/ に移す
  5. Nix を導入して再現性とロールバック性を上げる

まとめ

chezmoi + Nix は長年の問題を一気に解く選択でした:

課題 解決策
マシン移行が手作業 1コマンドで完了
マシン差分を記憶に頼る データ分層 + テンプレート
設定事故の復旧に時間がかかる 原子的な切り替え + ロールバック
設定を共有できない リポジトリ = 環境(公開可能)

ソースコード:https://github.com/signalridge/dotfiles
Star / Fork 歓迎です。困ったら Issue へ、改善は PR でも歓迎です。

Discussion