GitHub Actions における Nix バイナリキャッシュ 3 ツールの実測比較
はじめに
GitHub Actions の CI/CD に Nix を利用する際、バイナリキャッシュを活用することでビルド時間を短縮できます。
複数のキャッシュツールが存在しますが、スター数もまちまちで、人気だけでツールを選んでよいか判断に迷う場面がありました。
また、各ツールの性能を定量的に比較した記事は少なく、自分の環境に最適なツールを選ぶのが難しいと感じました。
本記事では GitHub Actions の実行速度(job 時間・build 時間)を基準に3 つのツールを比較しました。
比較は「公式バイナリキャッシュ(cache.nixos.org)があるパッケージのみの環境」と「公式バイナリキャッシュが無いパッケージを含む環境」の 2 パターンで実施しました。
検証に利用したコードを直接確認したい方は以下のレポジトリをご確認ください。
対象読者
- Nix を利用している方
- 前提:Nix 入門を読了済み
- GitHub Actions × Nix で CI/CD を構築し、ビルド時間の短縮を検討している方
- 各種キャッシュツールの違いを知り、「どれを選べばよいか」判断材料を得たい方
結論
基本的には cache-nix-action を利用し、必要に応じて cachix-action も比較検討する、といったスタイルが良いと思いました。
| 項目 | cachix-action | cache-nix-action | magic-nix-cache-action |
|---|---|---|---|
| 保存先 | Cachix | GitHub Actions Cache | GitHub Actions Cache |
| キャッシュ単位 | ストアパス単位 nix/store/<hash><name>
|
job ごとに 1 つ | ストアパス単位 nix/store/<hash><name>
|
| キャッシュ対象 | cache.nixos.org にないストアパス |
nix/ ほぼ全体 |
cache.nixos.org にないストアパス |
※デフォルト設定で利用する場合
環境別まとめ
公式バイナリキャッシュ(cache.nixos.org)があるパッケージのみの環境
キャッシュの効果は限定的でした。
使うなら cache-nix-action が有用です(約 10% 短縮)。

公式バイナリキャッシュが無いパッケージを含む環境(e.g. importNpmLock で Node.js パッケージを Nix で再現)
最有力は cache-nix-action、次点で cachix-action です(約 50% 短縮)。

記事の流れ
- 背景
- 各ツールの紹介
- 検証方法
- 検証結果
という流れで進行します。
1. 背景
1.1 Nix のビルドとキャッシュ
Nix のビルドはキャッシュによって最適化されています。
キャッシュツールの仕様理解に繋がるため、簡易的にビルドの流れを紹介します。
nix build コマンドを実行すると、flake.nix などの設定をもとにビルドレシピ(derivation)が生成されます。
そして、ビルド成果物(例:treefmt)のハッシュが算出されます。
packages.default = buildEnv {
name = "example";
paths = [ pkgs.treefmt ];
};
/nix/store/pnl4n8xandadzdp0jlnbkq4smkldprzs-treefmt-2.3.1
treefmt のバイナリを構築する前に、Nix は以下の順でビルド成果物のキャッシュの有無を確認します。
- ローカルの Nix ストアに同一パスがあるか
- なければ、設定されたバイナリキャッシュにあるか
- どちらにもなければ、一からビルド
デフォルトのバイナリキャッシュは cache.nixos.org です。
nixpkgs の多くはここにキャッシュが存在するため、初回からビルドをスキップして高速になります。
these 464 paths will be fetched (265.13 MiB download, 1391.91 MiB unpacked):
# ...
/nix/store/pnl4n8xandadzdp0jlnbkq4smkldprzs-treefmt-2.3.1
# ...
copying path '/nix/store/pnl4n8xandadzdp0jlnbkq4smkldprzs-treefmt-2.3.1' from 'https://cache.nixos.org'...
# ...
一方で、独自定義のパッケージは Nix ストア、cache.nixos.org に存在しないため、初回はキャッシュを活用できません。
these 464 paths will be fetched (265.13 MiB download, 1391.91 MiB unpacked):
# ...
# 公式バイナリキャッシュがある場合は、cache.nixos.org を利用
copying path '/nix/store/pnl4n8xandadzdp0jlnbkq4smkldprzs-treefmt-2.3.1' from 'https://cache.nixos.org'...
# ...
# 公式バイナリキャッシュが無い場合は、ビルド
building '/nix/store/d314dc7v1hakn4g9824yyrff2gxckg0h-zenn-cli-0.2.3.tgz.drv'...
# ...
1.2 ローカル / GitHub Actions でのビルドの差異
「ローカル環境」では、独自定義のパッケージであっても、2 回目以降はローカルの Nix ストアでのキャッシュによりビルドが高速化されます。
しかし、「GitHub Actions」では、実行ごとにまっさらな環境が立ち上がるため、ローカルの Nix ストアによる再利用が効きません。
つまり、公式バイナリキャッシュが無いパッケージを含む環境は、毎回ビルドが必要となり、CI/CD の実行時間が長くなる傾向にあります。
1.3 バイナリキャッシュツール
Nix には cache.nixos.org 以外の手段でビルド成果物を保存・再利用する仕組みが用意されています。
本記事では、GitHub Actions での Nix ビルドにフォーカスして、以下のキャッシュツールを比較します。
- cachix-action
- cache-nix-action
- magic-nix-cache-action
nix cache で検索した際に名前を見かけたツール達を対象にしました。
1.4 最適なツールはどれか
GitHub には複数のキャッシュツールが公開されており、スター数もまちまちです。
次項でデータを提示しますが、スター数だけで判断するなら magic-nix-cache-action が最も人気があります。
人気という理由だけで判断して良いのでしょうか?。
「自分の環境にとってベストなツール(=CI/CD が高速化できるツール)はどれか」を知りたいと思った事が本調査のきっかけです。
job 時間・build 時間を評価軸とし、初回ビルドと 2 回目のビルドの時間を計測して、キャッシュツールを定量的に比較しました。
参考資料
- Nix 全般のリファレンス
- Cache の解説ページ(分かりやすい)
- attic(self-hostable Nix Binary Cache server)
- cachix(バイナリキャッシュサーバー)
- バイナリキャッシュの解説記事
2. 各ツールの紹介
| 項目 | cachix-action | cache-nix-action | magic-nix-cache-action |
|---|---|---|---|
| 保存先 | Cachix | GitHub Actions Cache | GitHub Actions Cache |
| キャッシュ単位 | ストアパス単位 nix/store/<hash><name>
|
job ごとに 1 つ | ストアパス単位 nix/store/<hash><name>
|
| キャッシュ対象 | cache.nixos.org にないストアパス |
nix/ ほぼ全体 |
cache.nixos.org にないストアパス |
※デフォルト設定で利用する場合
2.1 cachix-action
- 外部のバイナリキャッシュサービス(Cachix)を利用
- ローカル・GitHub Actions・リポジトリ間・Job 間でキャッシュを共有可能
- 無料枠あり
- ただし、キャッシュは公開される
- プライベートは有料
- cache.nixos.org に存在しないモノのみをキャッシュする
2.2 cache-nix-action
- GitHub Actions のキャッシュを利用
- デフォルト設定では
/nix、~/.cache/nix、~root/.cache/nixがキャッシュ対象 - GitHub Actions Cache 上では大きな 1 ファイルとして保存される
- e.g. cache name:
nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/flake.lock') }}
- e.g. cache name:
- Nix の環境全体をキャッシュ&復元するイメージ(筆者の印象)
2.3 magic-nix-cache-action
- GitHub Actions のキャッシュを利用
- 細かい設定無しで手軽に利用できる(公式レポジトリの受け売り)
Use Magic Nix Cache, a totally free and zero-configuration binary cache for Nix on GitHub Actions.
- キャッシュの挙動は cachix に似ている(筆者の印象)
- cache.nixos.org に存在しないモノのみをキャッシュする
- のはずだが...今回の検証では cache.nixos.org にあるファイルもキャッシュしていた
- 詳細は検証結果に記載、解決策募集中
- 類似した issue が立っているので仕様かも?
- cache.nixos.org に存在しないモノのみをキャッシュする
2.4 各ツールのスター数

スター数の推移を見ると、magic-nix-cache-action が最も多くの支持を集めています。
一方で、2025 年以降は cache-nix-action の伸びが目立ちます。
この増加は、2025 年中頃に magic-nix-cache-action が一時的に非推奨となり、cache-nix-action へ移行するプロジェクトが増えた為と推測されます。
具体例:Hyprland
Hyprland リポジトリにて、2025 年 6 月に cache-nix-action へ移行する PR が確認できました。
2025/6/20
Describe your PR, what does it fix/add?
After https://github.com/DeterminateSystems/magic-nix-cache-action has been deprecated, we've been running Nix Actions without a cache for /nix/store. This meant that all dependencies had to be downloaded on each action run.
3. 検証方法
3.1 ビルドする環境
検証にあたり 2 種類の Nix 環境を用意しました。
- marp
- 公式バイナリキャッシュがあるパッケージのみの環境
-
pkgs.marp等を利用
- zenn
- 公式バイナリキャッシュが無いパッケージを含む環境
-
importNpmLockを利用して node_modules を Nix で再現する環境
3.1.1 marp - 公式バイナリキャッシュがあるパッケージのみの環境
Marp CLI を利用して Markdown からスライドを静的作成するのに利用している環境です。
pkgs.marp-cli の様に nixpkgs のパッケージを利用します。
そのため、ビルドでは公式バイナリキャッシュ(cache.nixos.org)を活用できます。
{
description = "Marp environment";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs =
{ nixpkgs, flake-utils, ... }:
flake-utils.lib.eachDefaultSystem (
system:
let
pkgs = nixpkgs.legacyPackages.${system};
in
rec {
packages = {
marp_build = pkgs.buildEnv {
name = "marp_build_tools";
paths = with pkgs; [
marp-cli
chromium
noto-fonts-cjk-sans
];
};
default = packages.marp_build;
};
devShells = {
default = pkgs.mkShell {
nativeBuildInputs = with pkgs; [
packages.marp_build
gh
];
};
};
apps = {
marp = {
type = "app";
program = "${pkgs.marp-cli}/bin/marp";
};
default = apps.marp;
};
}
);
}
3.1.2 zenn - 公式バイナリキャッシュが無いパッケージを含む環境
Zenn CLI を利用してローカル環境で記事を作成するのに利用している環境です。
Node.js のツールを利用するために、importNpmLock で node_modules を Nix で構築します。
importNpmLock によるビルドは公式バイナリキャッシュ(cache.nixos.org)が効きません。
この点が、marp 環境との明確な違いです。
{
description = "Zenn CLI environment";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs =
{ nixpkgs, flake-utils, ... }:
flake-utils.lib.eachDefaultSystem (
system:
let
pkgs = nixpkgs.legacyPackages.${system};
npmRoot = ./node-pkgs;
nodejs = pkgs.nodejs_24;
inherit (pkgs) importNpmLock;
npmDeps = importNpmLock.buildNodeModules {
inherit nodejs npmRoot;
};
in
rec {
packages = {
zenn_tools = pkgs.buildEnv {
name = "zenn_tools";
paths = with pkgs; [
treefmt
lychee
npmDeps
];
};
default = packages.zenn_tools;
};
devShells = {
zenn = pkgs.mkShell {
nativeBuildInputs = [
packages.zenn_tools
pkgs.go-task
importNpmLock.hooks.linkNodeModulesHook
];
inherit npmDeps;
};
node = pkgs.mkShell {
packages = [
nodejs
pkgs.npm-check-updates
];
};
default = devShells.zenn;
};
}
);
}
- 参考資料
3.2 ワークフロー
3.2.1 フローの内容について
ジョブ
マトリックス機能を利用して、ビルド環境 2 種 x(キャッシュツール 3 種 + ツール無し)= 8 パターンのジョブを定義しました。
トリガー
実行トリガーは手動(workflow_dispatch)です。
トリガー時に指定する変数
キャッシュ生成時とキャッシュ利用時の job 時間を比較するため、実行時に generate-cache または use-cache を指定できるようにしました。
処理内容に違いはなく、ジョブ名のプレフィックスとして利用しています。
ステップ
各ジョブのステップでは、各キャッシュツールの公式 README.md に記載されているサンプル構成を踏襲しました。
Nix のインストール方法はツールごとに異なりますが、あえて統一せず、それぞれの推奨方法に従う方針としています。
コード
name: "build"
on:
workflow_dispatch:
inputs:
phase:
description: "Choose cache phase. Only used for naming the job."
required: true
type: choice
options:
- generate-cache
- use-cache
jobs:
build:
strategy:
matrix:
cache_tool: [none, cachix-action, cache-nix-action, magic-nix-cache-action]
target_nix_env: [marp, zenn]
name: build_${{ matrix.target_nix_env }}_cachetool_${{ matrix.cache_tool }}_phase_${{ github.event.inputs.phase }}
runs-on: ubuntu-latest
concurrency:
group: ${{ matrix.target_nix_env }}_${{ matrix.cache_tool }}_${{ github.event.inputs.phase }}_${{ github.ref }}
cancel-in-progress: true
defaults:
run:
working-directory: ${{ matrix.target_nix_env }}
steps:
- uses: actions/checkout@v5
# === Install nix & setup cache tool ===
# none
- name: Install nix
uses: cachix/install-nix-action@v31
if: ${{ matrix.cache_tool}} == 'none'
# cachix Action
- name: Install nix
uses: cachix/install-nix-action@v31
if: ${{ matrix.cache_tool}} == 'cachix-action'
- name: Setup cache tool
uses: cachix/cachix-action@v16
with:
name: ryuryu333
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
if: ${{ matrix.cache_tool }} == 'cachix-action'
# cache-nix-action
- name: Install nix
uses: nixbuild/nix-quick-install-action@v30
with:
nix_conf: |
keep-env-derivations = true
keep-outputs = true
if: ${{ matrix.cache_tool}} == 'cache-nix-action'
- name: Setup cache tool
uses: nix-community/cache-nix-action@v6
with:
primary-key: nix-${{ matrix.target_nix_env }}-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/flake.lock') }}
restore-prefixes-first-match: nix-${{ matrix.target_nix_env }}-${{ runner.os }}-
gc-max-store-size-linux: 1G
purge: true
purge-prefixes: nix-${{ runner.os }}-
purge-created: 0
purge-last-accessed: 0
purge-primary-key: never
if: ${{ matrix.cache_tool }} == 'cache-nix-action'
# magic-nix-cache-action
- name: Install nix
uses: DeterminateSystems/nix-installer-action@v20
if: ${{ matrix.cache_tool}} == 'magic-nix-cache-action'
- name: Setup cache tool
uses: DeterminateSystems/magic-nix-cache-action@v13
if: ${{ matrix.cache_tool }} == 'magic-nix-cache-action'
# === Build ===
- run: nix build
# === Run test command ===
- run: nix develop -c zenn --version
if: ${{ matrix.target_nix_env }} == 'zenn'
- run: nix run .#marp -- --version
if: ${{ matrix.target_nix_env }} == 'marp'
3.2.2 ワークフローの実行手順
以下の手順でワークフローを実行しました。
-
GitHub Actions Cache を全て削除
gh cache delete --allを実行。 -
Cachix のキャッシュを全て削除
Cachix の画面よりCaches > ryuryu333 > Settings > Danger Zone > Clearをクリック。 -
ワークフロー
buildを手動実行
実行時にgenerate-cacheを選択。 -
全ジョブの完了を待機
-
ワークフロー
buildを再度手動実行
実行時にuse-cacheを選択。 -
全ジョブの完了を待機
-
手順 1 に戻る
この一連のフローを 4 回繰り返し、キャッシュ生成時とキャッシュ利用時の差分を検証しました。
3.3 ジョブ時間の集計
ジョブ時間の計測には GitHub API を利用しました。
各ジョブ・ステップのログを取得し、Python で集計・グラフ化しています。
コードは nix_cache_ci_experiments/reports/main.py に保存しています。
以下の run_id を対象としました。
| run_id | run_number | note |
|---|---|---|
| 18753771242 | 15 | 1 generate-cache |
| 18754054171 | 16 | 1 use-cache |
| 18777714953 | 21 | 2 generate-cache |
| 18777913273 | 22 | 2 use-cache |
| 18778308420 | 23 | 3 generate-cache |
| 18778547830 | 24 | 3 use-cache |
| 18779716921 | 27 | 4 generate-cache |
| 18779934804 | 28 | 4 use-cache |
以下のビルド一覧ページには試行錯誤の過程で実行した job も含まれるので、ご注意ください。
4. 検証結果
4.1 marp - 公式バイナリキャッシュがあるパッケージのみの環境
4.1.1 job 時間
| キャッシュツール | 時間(秒) | vs none |
|---|---|---|
| none | 36.50 | - |
| cachix-action | 42.00 | 115% |
| cache-nix-action | 31.75 | 87% |
| magic-nix-cache-action | 54.00 | 148% |

4.1.2 build 時間
| キャッシュツール | 時間(秒) | vs none |
|---|---|---|
| none | 24.00 | - |
| cachix-action | 25.25 | 105% |
| cache-nix-action | 9.25 | 39% |
| magic-nix-cache-action | 30.75 | 128% |
いずれも 2 回目のビルド(キャッシュを利用した状態)での結果

4.1.3 job 時間(キャッシュ生成時 vs キャッシュ利用時)
| キャッシュツール | キャッシュ生成時 job 時間(秒) |
vs none | キャッシュ利用時 job 時間(秒) |
vs none |
|---|---|---|---|---|
| none | 36.50 | - | 36.50 | - |
| cachix-action | 42.75 | 117% | 42.00 | 115% |
| cache-nix-action | 45.50 | 125% | 31.75 | 87% |
| magic-nix-cache-action | 428.50 | 1174% | 54.00 | 148% |

4.2 zenn - 公式バイナリキャッシュが無いパッケージを含む環境
4.2.1 job 時間
| キャッシュツール | 時間(秒) | vs none |
|---|---|---|
| none | 66.25 | - |
| cachix-action | 40.50 | 61% |
| cache-nix-action | 29.75 | 45% |
| magic-nix-cache-action | 66.50 | 100% |

4.2.2 build 時間
| キャッシュツール | 時間(秒) | vs none |
|---|---|---|
| none | 51.50 | - |
| cachix-action | 21.25 | 41% |
| cache-nix-action | 9.00 | 17% |
| magic-nix-cache-action | 38.50 | 75% |
いずれも 2 回目のビルド(キャッシュを利用した状態)での結果

4.2.3 job 時間(キャッシュ生成時 vs キャッシュ利用時)
| キャッシュツール | キャッシュ生成時 job 時間(秒) |
vs none | キャッシュ利用時 job 時間(秒) |
vs none |
|---|---|---|---|---|
| none | 66.25 | - | 66.25 | - |
| cachix-action | 99.00 | 149% | 40.50 | 61% |
| cache-nix-action | 108.25 | 163% | 29.75 | 45% |
| magic-nix-cache-action | 377.00 | 569% | 66.50 | 100% |

4.3 キャッシュ容量
補足として、各ツールが生成したキャッシュの容量を比較しました。
対象は、marp・zenn 両環境のビルドを完了した後に生成されたキャッシュです。
| キャッシュツール | 保存場所 | ファイル数 | 容量(MB) |
|---|---|---|---|
| cachix-action | cachix | 287 | 69 |
| cache-nix-action | GitHub Actions Cache | 2 | 1130 |
| magic-nix-cache-action | GitHub Actions Cache | 2202 | 1177 |
詳細データを見たい人用
キャッシュをすべて削除した後、build #33 を実行し、削除せずに使用状況を確認しました。
# build #33 を実行後、キャッシュを削除していない状態で実行
$ gh api repos/ryuryu333/nix_cache_ci_experiments/actions/cache/usage
{
"full_name": "ryuryu333/nix_cache_ci_experiments",
"active_caches_size_in_bytes": 2307766854,
"active_caches_count": 2202
}



おわりに
今回の検証では、3 種のキャッシュツールを定量的に比較し、環境構成によってキャッシュ効果がどのように変化するかを評価しました。
結果として、ツールごとに挙動や得意なケースが異なり、プロジェクトの構成次第で最適解が変わると分かりました。
今後は cache-nix-action をメインに運用しつつ、 実際のプロジェクトで得られた知見も記事にしたいと考えています。
Nix は日本語文献がまだ少ない分野ですが、少しずつ実例を増やしていけたらと思います。
Discussion