actions/setup-nodeは、GitHub ActionsのランナーにNode.jsを入れてPATHを通し、npm・yarn・pnpmの依存キャッシュまで受け持つ公式アクションです。現行版は2026年10月8日公開のv7.1.0で、@v7のタグもこの版を指しています。v7.1.0ではnode-version-fileがmise.tomlと絶対パスを読めるようになり、導入したNode.jsの版を照合する処理も入りました。本記事では入力と既定値、版指定の統一、キャッシュが何を省くのかの実測、v4からの移行で壊れる箇所、npm公開ジョブの組み方までを扱います。ワークフローの全体像はGitHub Actionsの基本構造と使い方を解説した記事、ビルドとテストの通し手順はbuild.ymlの書き方を解説した記事にまとめています。
まとめ:actions/setup-nodeで最初に決める版指定とキャッシュの持ち方
決めることは2つです。版はnode-version-fileで.nvmrc・package.json・mise.tomlのどれかを読ませ、ローカルとCIの指定を1か所に寄せます。node-versionとnode-version-fileの両方を省略したジョブは、ubuntu-latestの26.04移行で既定のNode.jsが22から24へ変わるので、今のうちに明示してください。
キャッシュは通常のテストジョブならcache: npmのように明示し、npmへの公開や本番デプロイのような特権ジョブではcacheの明示指定を外し、package-manager-cache: falseで自動キャッシュも止めます。保存されるのはnpmのグローバルキャッシュで、node_modulesではありません。依存251パッケージで測ると、短縮できたのはnpm ciの約3秒でした。
v4以前から上げるときに確かめるのは3点です。セルフホストランナーがv2.327.1以上か、yarnやpnpmでcacheを明示しているか、registry-urlを使うジョブでNODE_AUTH_TOKENを渡しているか。
actions/setup-nodeを動かす最小のワークフローとv7.1の入力一覧
checkoutとsetup-nodeとnpm ciを並べる最小構成
以下は、リポジトリ直下に版を記載した.nvmrc、整合するpackage.jsonとpackage-lock.json、testスクリプトがある場合の最小構成です。
# .github/workflows/ci.yml
name: ci
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version-file: '.nvmrc'
cache: 'npm'
- run: npm ci
- run: npm test
npm installではなくnpm ciを使うのは、npm公式のnpm ciの説明のとおり、package-lock.jsonとpackage.jsonが食い違うとエラーで止まり、ロックファイルを書き換えないからです。setup-nodeの前に置くcheckoutの入力はactions/checkoutの主要入力と既定値を整理した記事で扱っています。
action.ymlで確認したv7.1.0の入力12個と出力4個
入力の定義はv7.1.0のaction.ymlが正本です。入力は12個で、v7.0.0から増減はありません。
| 入力 | 既定値 | 用途 |
|---|---|---|
| node-version | なし | 版の指定 |
| node-version-file | なし | 版を書いたファイル |
| check-latest | false | 最新パッチの確認 |
| architecture | ランナーに従う | x64・arm64など |
| cache | なし | npm・yarn・pnpm |
| package-manager-cache | true | npmの自動キャッシュ |
| cache-dependency-path | なし | ロックファイルの場所 |
| registry-url | なし | .npmrcの生成 |
| scope | GitHub Packagesではリポジトリ所有者 | 認証スコープ。通常は未指定 |
| token | github.comではgithub.token、それ以外は空 | 配布物の取得 |
| mirror | なし | 配布元の差し替え |
| mirror-token | なし | ミラーの認証 |
出力はnode-version、cache-hit、v7.0.0で増えたcache-primary-keyとcache-matched-keyの4つです。実行ランタイムはnode24で、ジョブ末尾のpost処理でキャッシュを保存します。post処理にはsuccess()の条件が付いているので、途中のステップが失敗したジョブではキャッシュが保存されません。
Node.js本体の取得順序とv7.1.0で入った版の照合
check-latestがfalseのとき、アクションはまずランナーのツールキャッシュから条件に合う版を探します。無ければactions/node-versionsのマニフェストから取得し、そこに無ければnodejs.orgの配布物を直接ダウンロードします。v7.1.0ではマニフェストの取得に失敗したとき、最大3回まで試行するようになりました。
同じv7.1.0で、導入後にnode --versionの結果とツールキャッシュのディレクトリ名を突き合わせる処理も入っています。食い違うとNode v24.10.0 installation failed, likely due to an incomplete or corrupted download.のようなエラーで止まります。セルフホストランナーでツールキャッシュが壊れていると、v7.0.0までは誤った版のまま進んでいたジョブが、v7.1.0では失敗に変わります。
範囲指定の扱いにも注意が要ります。node-version: 24や^24.3は、ツールキャッシュにある条件を満たす版のうち最も新しいものに解決され、nodejs.orgの最新パッチまでは見に行きません。セキュリティ修正をその日のうちに取り込みたいジョブに限ってcheck-latest: trueを付けてください。
ubuntu-latestの26.04移行とNode 26のLTS昇格で変わる版の解決
2026年10月下旬は、ワークフローを1行も変えていなくても、使われるNode.jsの版が変わりうる時期です。原因は2つ重なっています。
版指定のないジョブにおける既定Node.jsの22から24への変更
GitHubの2026年9月17日の告知によると、ubuntu-latestは2026年10月19日から11月19日にかけて、Ubuntu 24.04から26.04へ段階的に切り替わります。ランナーイメージの一覧(2026年10月23日のイメージ)では、既定でPATHに入るNode.jsが次のように違います。
| ランナー | PATH上の既定 | ツールキャッシュ |
|---|---|---|
| ubuntu-24.04 | 22.23.3 | 22.23.3・24.21.0 |
| ubuntu-26.04 | 24.21.0 | 22.23.3・24.21.0 |
出典はUbuntu 24.04のイメージ一覧とUbuntu 26.04のイメージ一覧です。setup-nodeは、node-versionとnode-version-fileのどちらからも版を指定しない場合、PATH上のNode.jsをそのまま使います。版を書いていないジョブは、移行のタイミングで22から24へ黙って切り替わります。runs-onのラベルを固定する判断はruns-onのラベル指定と-latest更新を解説した記事で扱っています。
lts/*のNode 26への切替条件とツールキャッシュ未収録時の取得
Node.jsのリリース計画では、Node.js 26のLTS入りは2026年10月28日です。node-version: lts/*はnode-versionsのマニフェストで最も新しいLTSに解決されるため、マニフェストに26がLTSとして載った時点で24から26へ移ります。上の表のとおり、ランナーのツールキャッシュにあるのは22と24だけです。26がツールキャッシュに未収録のGitHubホステッドランナーでは、ジョブごとにダウンロードが必要です。
本番がNode.js 24のまま動いているなら、lts/*ではなく24と書いてください。26への移行判断はNode.js LTSの確認・固定・移行の手順を解説した記事に譲ります。
node-version-fileでCIとローカルの版指定を統一する設定
読める5形式とv7.1.0で増えたmise.toml・絶対パス
node-version-fileが受け付けるのは.nvmrc、.node-version、.tool-versions、package.jsonに、v7.1.0で加わったmise.tomlです。node-versionと両方書くとnode-versionが勝ち、警告が出ます。移行途中に両方残すと、ファイルを書き換えてもCIの版が変わりません。
v7.0.0とv7.1.0の配布物(dist/setup/index.js)を手元で同じ条件で動かし、解決結果を比べました。ツールキャッシュに各版のディレクトリと版表示を模擬する実行ファイルを置き、入力の解析と版の選択を確認した結果です。各版のNode.js本体の動作検証ではありません。
| node-version-file | v7.0.0 | v7.1.0 |
|---|---|---|
| mise.toml(node = “24.10.0”) | [tools]と解釈し失敗 | 24.10.0 |
| package.json(devEngines ^24.3) | 24.12.0 | 24.12.0 |
| 絶対パスの.nvmrc(22.20.0) | ファイル不在で失敗 | 22.20.0 |
v7.0.0はmise.tomlの1行目[tools]を版の文字列として読み、Unable to find Node version '[tools]'で止まりました。絶対パスはワークスペースの後ろに連結され、存在しないパスを探しに行きます。v7.1.0の変更点には、Composite Actionから${{ github.action_path }}配下の.nvmrcを渡せるようにする目的がコメントで書かれています。mise.tomlを使うなら@v7.0.0への固定は外してください。miseの設定はmise.tomlでツールを束ねる導入手順を解説した記事で扱っています。
package.jsonの参照順序とdevEngines.runtimeでCIの版を絞る書き方
package.jsonを渡したときの参照順は公式のadvanced-usage.mdに書かれています。
volta.nodedevEngines.runtimeのうち"name": "node"の項目engines.nodevolta.extendsで指定したファイルを辿って同じ順に探す
devEngines.runtimeの読み取りは2026年3月4日公開のv6.3.0で入りました。engines.nodeに^22 || ^24のような幅を書いて利用者向けの対応範囲を示し、CIで使う版だけをdevEngines.runtimeで絞れます。上の実測でも、engines.nodeよりdevEngines.runtimeの^24.3が優先され、ツールキャッシュで最も新しい24.12.0が選ばれました。
lts/*や24.xなど版指定の書式とmatrixで複数版を回す例
版指定には24や24.8.0のようなSemVer表記のほか、lts/*、lts/-1、lts/jodのようなnvmと同じ別名、latestが使えます。latestは常にnodejs.orgの最新版に解決されてツールキャッシュに当たりにくく、取得元のレート制限に当たりうるとREADMEに記載があります。
ライブラリを配布する側なら、サポート対象の版をmatrixで並べます。
jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node: ['22', '24', '26']
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: ${{ matrix.node }}
cache: 'npm'
- run: npm ci
- run: npm test
キャッシュのキーにNode.jsの版は入らないため、3つの版で1つのキャッシュを共有します。組み合わせの足し引きはmatrixのinclude・excludeを解説した記事で確認できます。
cache入力で依存取得を短縮する設定とnode_modulesを保存しない仕組み
保存されるのはグローバルキャッシュでキーは完全一致のみ
setup-nodeのキャッシュは内部でactions/cacheを呼びます。保存対象はnpmならnpm config get cacheが指すディレクトリ、pnpmならpnpm store pathのストアで、node_modulesではありません。
v7.1.0のソースでは、キーはnode-cache-<OS>-<アーキテクチャ>-<パッケージマネージャー>-<ロックファイルのハッシュ>の形で組まれます。復元は完全一致のキーだけで、前方一致の代替キーを渡すのはYarn Berryで依存をローカル管理している場合に限られます。ロックファイルを1行変えると、前回のキャッシュは使われずダウンロードからやり直しです。
探すロックファイルは、npmならpackage-lock.json・npm-shrinkwrap.json・yarn.lock、pnpmならpnpm-lock.yamlです。リポジトリ直下に無いとDependencies lock file is not foundで止まります。ロックファイルをコミットしていないなら、cacheを書かず、package-manager-cache: falseで自動キャッシュも止めるよう公式は案内しています。
npm ciのキャッシュあり・なしの実測と効果の上限
キャッシュで縮む時間を、手元のmacOS(Node.js 26.5.0・npm 11.17.0)で測りました。eslint・typescript・vitest・express・zodなどを入れた、ロックファイル上251パッケージのプロジェクトで、node_modulesを消してnpm ciを3回ずつ実行した結果です。
| 条件 | npm ciの所要時間 |
|---|---|
| npmキャッシュ空 | 8.73〜9.26秒(中央値8.96秒) |
| npmキャッシュ復元済み | 5.41〜7.70秒(中央値5.73秒) |
縮んだのは中央値で約3.2秒、3割強です。キャッシュありでも中央値で5.73秒かかりましたが、今回の計測では処理別の所要時間までは分離していません。npmキャッシュは19MB、展開後のnode_modulesは75MB・3,376ファイルでした。GitHubホステッドランナーでの短縮幅は、ネットワークや依存関係の条件が異なるため、今回のローカル計測だけでは判断できません。
もう1点、npm ciは既存のnode_modulesを削除してから入れ直します。node_modulesに目印のファイルを置いて実行すると、実行後には消えていました。actions/cacheでnode_modulesを復元したあとにnpm ciを走らせると、復元した中身は捨てられます。
node_modulesごと保存したいときのactions/cache併用
展開の時間まで省きたいなら、setup-nodeのcacheは使わず、actions/cacheでnode_modulesを保存し、ヒットしたときはnpm ciを飛ばします。
- id: node
uses: actions/setup-node@v7
with:
node-version-file: '.nvmrc'
package-manager-cache: false
- id: nm
uses: actions/cache@v6
with:
path: node_modules
key: nm-${{ runner.os }}-${{ runner.arch }}-${{ steps.node.outputs.node-version }}-${{ hashFiles('package-lock.json') }}
- if: steps.nm.outputs.cache-hit != 'true'
run: npm ci
キーにsetup-nodeの出力node-version(実際に入った版)を含めているのは、ネイティブアドオンを含むnode_modulesはNode.jsの版をまたいで使い回せないからです。.nvmrcのハッシュでは、中身が24やlts/*のとき、解決される版が変わっても同じキーのままになります。ヒットしたジョブではnpm ciごと飛ばすので、prepareなどのライフサイクルスクリプトも走りません。node_modulesの外に生成物を作るプロジェクトは、その処理を別ステップで実行してください。保存量はグローバルキャッシュの数倍になり、上の実測では約4倍でした。リポジトリあたりのキャッシュ容量を圧迫する点も含め、キー設計と復元されない原因の切り分けはactions/cacheのkey設計を扱った記事で解説しています。
モノレポでcache-dependency-pathを指定する書き方
ロックファイルがサブディレクトリにあるときは、cache-dependency-pathでパスを渡します。ワイルドカードと複数行の指定に対応しています。
- uses: actions/setup-node@v7
with:
node-version-file: '.nvmrc'
cache: 'npm'
cache-dependency-path: |
apps/web/package-lock.json
apps/api/package-lock.json
複数のロックファイルを1つのキーにまとめると、どれか1つが変わっただけで全体が作り直しになります。サービスごとにジョブを分けているなら、ジョブごとに自分のロックファイルだけを渡す方がヒット率は上がります。
pnpmとyarnでcacheを効かせる前にパッケージマネージャーを入れる順番
cache: pnpmはpnpm v6.10以上が対象です。setup-nodeはキャッシュの場所をpnpm自身に問い合わせるため、その時点でpnpmコマンドが無いとUnable to locate executable file: pnpmで失敗します。pnpm/action-setupをsetup-nodeより前に置いてください。
- uses: actions/checkout@v7
- uses: pnpm/action-setup@v6
with:
version: 10
- uses: actions/setup-node@v7
with:
node-version-file: '.nvmrc'
cache: 'pnpm'
- run: pnpm install --frozen-lockfile
yarnはClassic(v1)とBerry(v2以降)の両方をキャッシュできます。pnpmの共有ストアの仕組みはpnpmの共有ストアとモノレポ運用を解説した記事で整理しています。
v4からv7.1へ上げるときに壊れる箇所の確認手順
v4のnode20ランタイムと2026年9月23日のNode 20削除
v4系の最終版v4.4.0は、action.ymlのruns.usingがnode20のままです。2026年9月23日の告知で、Node 20はGitHub Actionsのランナーから外れ、JavaScriptアクションはNode 24で実行されるようになりました。一時的な回避策だったACTIONS_ALLOW_USE_UNSECURE_NODE_VERSIONも使えません。告知はNode 24対応の最新版へ上げるよう求めているので、@v4のワークフローは下の3つを確かめてから@v7へ上げてください。
v5の自動キャッシュとランナーv2.327.1要件
2025年9月4日公開のv5.0.0で、cacheを書いていなくても、package.jsonにpackageManagerの記載があればキャッシュが自動で有効になりました。同時に実行ランタイムがnode24へ上がり、ランナーv2.327.1以上が必要になっています。GitHubホステッドランナーは自動で更新されます。古いランナーを固定したセルフホスト環境やGitHub Enterprise Serverでは、先にランナーの版を確かめてください。
v6で自動キャッシュがnpm限定になった条件とalways-auth削除
2025年10月14日公開のv6.0.0で、自動キャッシュの対象はnpmだけに絞られました。条件は、devEngines.packageManagerかトップレベルのpackageManagerがnpmを指し、cacheを明示していないことです。yarnやpnpmのプロジェクトは、v5で自動で効いていたキャッシュがv6で外れます。上げた後にジョブが遅くなったら、cache: pnpmのように明示すれば戻ります。2025年12月3日公開のv6.1.0ではalways-authの処理が削除されたので、ワークフローに残っていれば消してください。
v7のNODE_AUTH_TOKENダミー廃止でYarn Classicが落ちる条件
2026年7月14日公開のv7.0.0の変更は、内部のESM移行、キャッシュキーを返す2つの出力の追加、ミラー認証の修正、NODE_AUTH_TOKENのダミー値の廃止です。影響が出るのは最後の1つです。従来はregistry-urlを指定すると、トークンを渡していなくてもダミー値が環境変数に入っていました。READMEによると、v7ではregistry-urlを指定してNODE_AUTH_TOKENを渡さない構成で、Yarn Classic(1.x)や古いnpmが失敗し、pnpmは警告を出す場合があります。
grep -rn "registry-url" .github/workflowsで該当ジョブを洗い出し、トークンを渡すかregistry-urlを外してから上げてください。アクションをコミットSHAで固定している場合の追随手順はGitHub ActionsのSHA固定とEnforce設定の記事、メジャー更新を自動で受け取る設定はGitHub ActionsとDependabotの連携設定の記事にまとめています。
registry-urlとTrusted Publishingでnpm公開ジョブを組む手順
registry-urlは、通常はRUNNER_TEMP配下に.npmrcを書き出し、NPM_CONFIG_USERCONFIGでそのファイルを指定して、認証情報をNODE_AUTH_TOKENから読ませる設定です。公開ジョブではこの仕組みとキャッシュの両方に注意が要ります。
OIDCで公開するためのnpm 11.5.1要件とid-token権限
npmのTrusted Publishingを使うと、長期のnpmトークンをシークレットに置かず、OIDCの短命トークンで公開できます。advanced-usage.mdでは、npm 11.5.1以上が必須、Node.js 24以降が推奨です。
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: '24'
registry-url: 'https://registry.npmjs.org'
package-manager-cache: false
- run: npm ci
- run: npm run build --if-present
- run: npm publish
npm側のTrusted Publisher設定と、リポジトリ・ワークフローファイル名・Environmentの組が完全に一致しないと、パッケージが存在していてもE404で失敗します。id-token: writeを含む権限の絞り方はGITHUB_TOKENの既定権限と最小権限を解説した記事を参照してください。
プライベートパッケージを入れるジョブでinstallスクリプトを止める理由
プライベートパッケージを入れるジョブは、NODE_AUTH_TOKENをシークレットから渡します。advanced-usage.mdの例は、そのステップをnpm ci --ignore-scriptsにし、続くステップでnpm rebuildを実行する構成です。悪意あるpostinstallスクリプトがトークンを読み取る経路を断つためで、package-manager-cache: falseも併せて指定されています。
setup-nodeのキャッシュを切る場面とコンテナで版を固定する判断基準
キャッシュを切るべきジョブの権限と効果が薄いリポジトリの条件
切るべきジョブは3種類です。npmやGitHub Packagesへ公開するジョブ、本番環境の資格情報を持つデプロイジョブ、pull_request_targetのように書き込み権限付きで動くジョブ。いずれもpackage-manager-cache: falseを明示し、cacheも書きません。公式は、汚染されたキャッシュが復元されると、OIDCトークンを含む資格情報が攻撃者の制御するコードへ渡りうると説明しています。package.jsonにpackageManagerでnpmを書いただけで、書いた覚えのないキャッシュが公開ジョブで有効になるのがv6以降の既定です。
依存が少ないリポジトリでは、キャッシュの復元・保存を含むジョブ全体の時間を測って採否を決めます。上の実測では251パッケージで短縮は約3秒でした。GitHub上での復元・保存にかかる時間は測っていないので、自分のジョブのログで差し引きを確かめてください。テストジョブでは使い、特権ジョブでは切る。読み取り専用のキャッシュ運用では、復元元が信頼できることを別途確認したうえで、actions/cache/restoreで読み取りだけを行い、書き込みはテストジョブに任せる構成がadvanced-usage.mdに載っています。
setup-nodeを使わずコンテナイメージでNodeを固定する判断基準
setup-nodeはツールキャッシュの版を優先するので、24指定のままだと、ランナーイメージの更新で24.21.0から次のパッチへ変わります。Node.jsのパッチ版だけをそろえたいなら、node-version: 24.21.0のように完全な版で固定すれば足ります。OSやシステムライブラリまで本番とそろえる案件では、ジョブのcontainer:に本番と同じイメージのダイジェストを指定する方が確実です。
複数の版で回すライブラリや、起動の速さを優先する社内ツールは、setup-nodeのままで十分です。コンテナ化は、「OSやライブラリの差で不具合が出たことがある」「監査で実行環境の再現性を求められる」のどちらかに当てはまるまで見送ってかまいません。移すときは、イメージの取得を含めたジョブ全体の時間を前後で比べてください。権限設計やキャッシュとデプロイの分離まで含めてCI全体を見直したい場合は、DevOps・CI/CD導入支援で設計と移行を引き受けています。
よくある質問
actions/setup-node@v4はまだ使えますか?
v4はaction.ymlの実行ランタイムがnode20のままで、2026年9月23日以降、ランナーはJavaScriptアクションをNode 24で実行しています。GitHubの告知はNode 24対応の最新版へ上げるよう求めているので、@v7へ上げてください。途中の版を経由する必要はありませんが、v5・v6・v7それぞれの既定変更を先に確かめます。
actions/setup-nodeのcacheを指定しても速くならないのはなぜですか?
保存されるのはnpmのグローバルキャッシュで、node_modulesではないためです。npm ciは毎回node_modulesを消して展開し直すので、省けるのはダウンロードの時間だけです。251パッケージの実測では、短縮は中央値で約3.2秒でした。npmでは、変更後のロックファイルに対応するキャッシュがまだ無ければミスになり、前のキャッシュは使われません(Yarn Berryの一部構成だけは代替キーで復元されます)。
node-versionとnode-version-fileはどちらを使うべきですか?
アプリケーションならnode-version-fileで.nvmrc・package.json・mise.tomlのどれかを読ませる方法を勧めます。ローカルとCIの版指定が1か所にまとまります。mise.tomlを読めるのはv7.1.0以降です。複数の版で検証するライブラリはmatrixとnode-versionの組み合わせが向いています。両方を書くとnode-versionが優先されます。
setup-nodeでNODE_AUTH_TOKENはいつ必要ですか?
registry-urlを指定して、トークン認証でnpmやGitHub Packagesへ公開する、またはプライベートパッケージを入れるジョブで必要です。v7でダミー値の自動設定が廃止されたため、渡さないとYarn Classicや古いnpmが失敗します。Trusted Publishing(OIDC)で公開する場合はNODE_AUTH_TOKENを使わないので、シークレットは不要です。
pnpmでcache: pnpmを指定するとエラーになるのはなぜですか?
setup-nodeの実行時点でpnpmコマンドが無いためです。キャッシュの保存先をpnpmに問い合わせる処理が走り、Unable to locate executable file: pnpmで止まります。pnpm/action-setupをsetup-nodeより前のステップに置いてください。pnpmはv6.10以上が対象で、インストールは–frozen-lockfileを付けて実行します。