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

ソースコードは公開しています:https://github.com/signalridge/dotfiles
Star / Fork 歓迎です。質問や改善提案は Issue へどうぞ。
はじめに
開発者なら、こんな「つらさ」を経験したことはありませんか?
- 新しい Mac に乗り換えるたびに、丸一日かけてツールを入れ直す
- 会社PCと個人PCで設定が揃わず、便利なエイリアスや関数をつい忘れてしまう
-
.zshrcが肥大化して触るのが怖い(壊しそう) - 設定を同僚に共有したいのに、再現できない(「自分の環境では動く」)
私も同じでした。そこで以下の要件を課しました:
- 再現可能:別のマシンでも環境が「完全に同じ」になる
- プロファイル対応:仕事用 / 個人用を共存させ、差分を明示できる
- 復旧可能:設定破壊が起きても、すぐ前の版へ戻せる
- 共有可能:公開できる一方で、機密情報は安全に守る
- 保守可能:日常更新を標準手順に落とし込み、手作業に依存しない
最終的に 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 を選んだ決め手:
-
段階的に始められる — 「まず
.zshrcだけ」から拡張できる - Nix がない環境でも動く — SSH 先、Codespaces、同僚のマシンでも OK
- 設定ファイルの「見た目」が変わらない — ほぼそのままの形で Git 管理
-
暗号化がシンプル —
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 の利点:
-
再現性 —
flake.lockで依存バージョンを固定 - 原子的更新 — 切り替えは一括で行われる
- ロールバック — 失敗は世代を戻すだけで復旧
- macOS 設定も管理 — Dock / Finder / Trackpad などをコード化
- 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
段階的に足すおすすめの順序:
-
.chezmoidata.yamlで shared/work/private の分層を作る - 変わりやすい設定を
.tmpl化する - age で機密ファイルを暗号化
- インストール手順を
.chezmoiscripts/に移す - Nix を導入して再現性とロールバック性を上げる
まとめ
chezmoi + Nix は長年の問題を一気に解く選択でした:
| 課題 | 解決策 |
|---|---|
| マシン移行が手作業 | 1コマンドで完了 |
| マシン差分を記憶に頼る | データ分層 + テンプレート |
| 設定事故の復旧に時間がかかる | 原子的な切り替え + ロールバック |
| 設定を共有できない | リポジトリ = 環境(公開可能) |
ソースコード:https://github.com/signalridge/dotfiles
Star / Fork 歓迎です。困ったら Issue へ、改善は PR でも歓迎です。
Discussion