actions/upload-artifactは、ジョブが作ったファイルを後続ジョブや人の手元へ渡すためのアクションです。3行で動きます。ただしv4で入った破壊的変更を知らないまま書くと、マトリックスの2セル目で「同じ名前のアーティファクトが既に存在する」と落ちます。この記事では受け渡しの最小構成、v4で変わった不変性とジョブ単位の保管、upload側がv7でdownload側がv8という1つずれたバージョン対応、retention-daysと保持期間の上限、キャッシュとの線引き、パーミッション欠落と隠しファイルの事故までを扱いました。ワークフローの基本構造はGitHub Actionsとは?できること・使い方とCI/CD自動化の解説記事、テスト実行の組み方はGitHub Actionsでビルド・自動テストを設定する方法を先に押さえてください。
まとめ:アーティファクト設計で先に決める4つの前提
第一に、ジョブは1つずつ別のランナーで動く仕組みです。ビルドで作ったバイナリもテストレポートも、ジョブが終われば消えます。次のジョブへ渡す手段はアーティファクトかキャッシュの2択で、この2つは目的が違います。
第二に、v4以降のアーティファクトは不変です。作成後に中身を足せません。同じ名前で2回上げると2回目が失敗します。マトリックスで回すなら、名前にセルの識別子を付けるのが前提になります。
第三に、バージョン番号は2つのアクションでずれています。2026年8月25日時点の最新はupload-artifactがv7.0.1、download-artifactがv8.0.1です。同じ日にリリースされた組でも番号が1つ違うため、揃えようとすると噛み合いません。
第四に、保持期間の既定は90日です。retention-daysで短くできますが、上限はリポジトリの公開設定で分かれます。パブリックは最大90日、プライベートと内部リポジトリは最大400日。設定変更は新しく作られる分にしか効かず、既に積み上がった分は残り続けます。
ジョブ間でファイルを受け渡すupload-artifactの基本構造
ステップ間で共有できるものと、ジョブ間で共有できないもの。この区別がつかないまま設定を書くと、受け取り側で「ファイルが無い」と止まります。
ジョブごとに別のランナーで動くためファイルが引き継がれない前提
同じジョブ内のステップは、同じランナー上の同じ作業ディレクトリを共有します。ジョブが変われば話が別です。新しいランナーが割り当てられ、$GITHUB_WORKSPACEは空の状態から始まります。前のジョブが吐いたdist/配下は、そこには存在しません。
この断絶を埋めるのがアーティファクトです。アップロードされたファイルはワークフロー実行に紐づいて保管され、後続ジョブからダウンロードできるほか、実行結果ページの下部とREST APIからも取得できます。よく置かれるのは、ビルド済みバイナリ、テストレポート、カバレッジ、失敗時のスクリーンショット、デバッグ用のログです。
nameとpathの指定で決まるアーティファクト内部のディレクトリ構造
入力は2つ覚えれば動きます。nameはアーティファクトの名前で、省略時はartifact。pathは必須で、ファイル・ディレクトリ・ワイルドカードのいずれかを取ります。
展開後の構造はpathの書き方で決まる仕組みです。複数行で複数パスを渡した場合、ルートになるのはそれらの最小共通祖先です。ワイルドカードを使うと、最初のワイルドカードより手前の階層が畳まれます。path/to/*/directory/foo?.txtと書けば、アーティファクト内はsome/directory/foo1.txtのようにpath/to/が消えた形で入ります。除外は先頭に!を付けた行で指定しますが、除外行はルート決定に影響しません。
もう1つ、if-no-files-foundの既定値がwarnである点に注意してください。ビルドが空振りして成果物が1つも無くても、警告が出るだけでジョブは成功します。デプロイ前段のように「必ず何か出るはず」の場所ではerrorへ変えておくと、後段で初めて気づく事態を避けられます。
needsで順序を作りdownload-artifactで展開するまでの4手順
受け渡しの最小構成は次の順で組み立てます。
- ビルドジョブの最後に
actions/upload-artifact@v7を置き、nameとpathを指定する - 受け取る側のジョブに
needs:を書き、ビルドジョブの完了を待たせる - 受け取る側で
actions/download-artifact@v8に同じnameと展開先pathを渡す ls -Rで展開後の構造を1度だけ確認し、期待した階層と合っているか照合する
ダウンロード側でpathを省くと$GITHUB_WORKSPACE直下に展開されます。nameを省いた場合は、その実行に存在する全アーティファクトが名前ごとのディレクトリへ分かれて降りてきます。4手順目を省く人が多いのですが、階層のずれはここでしか見つかりません。ファイルではなく短い値を渡す経路と、ジョブをどこで割るかの判断はGitHub Actionsのneedsとoutputsの実務にまとめてあります。再利用ワークフローをまたぐ場合も、ファイルはこの経路です。Reusable Workflows(GitHub Actions)とは?workflow_callでの作成・呼び出しの解説で扱うoutputsはテキストしか運べないため、成果物はアーティファクト経由に分けてください。
v4以降に変わった不変性・同名不可・ジョブ単位という3つの前提
2023年12月にv4が一般提供へ移り、v3以前とは互換性のない仕様になりました。日本語の解説記事の多くはv3時代の書き方を引きずっており、ここが事故の発生源です。
作成後に書き換えられない不変性と同名アップロードが落ちる理由
v3では同じ名前のアーティファクトへ複数ジョブから書き足せました。並行アップロードで中身が壊れる事故が起き、v4はこれを不変に変えています。READMEの表現は「アーティファクト名は一意でなければならない。作成されたアーティファクトは冪等であり、複数のジョブが同一のアーティファクトを変更することはできない」です。
2回目の同名アップロードは、警告ではなく失敗として返ります。overwriteの既定値がfalseで、同名が存在する時点でアクションが落ちる設計だからです。
引き換えに得たものもあります。保管の単位がワークフローからジョブへ変わり、アップロード直後からAPIでダウンロードできるようになりました。v3では実行が終わるまで待つ必要がありました。公式のリリース告知は最大10倍の性能改善にも触れています。artifact-id・artifact-url・SHA-256のartifact-digestがステップ出力で取れるのも、この世代からです。
overwrite:trueで置き換えたときにIDが変わる挙動と使いどころ
overwrite: trueは上書きではありません。同名の既存アーティファクトを削除してから新しく作る動きで、結果としてIDが変わります。前のIDを控えて参照していた後続ステップは、そのままでは取得に失敗します。
使ってよいのは、再実行で最新版だけ残したい配布物のように、名前で引く前提の構成です。避けるべきなのは、artifact-idsで個別に引く構成と、複数ジョブが同じ名前へ書き込もうとしている構成の2つ。後者をoverwriteで通してしまうと、どのジョブの成果物が残るかが実行順序に左右されます。名前を分けるほうが正解です。
マトリックスの各セルへ接尾辞を付けて名前衝突を避ける命名規則
3OS×3バージョンで9セル回す構成を、v3の感覚でname: my-artifactと書くと、最初に終わった1セル以外が全滅します。公式の移行ドキュメントが示す書き換えは、名前にマトリックス変数を差し込む形です。name: binary-${{ matrix.os }}-${{ matrix.version }}と書けば、binary-ubuntu-latest-aのように9個が別々に残ります。
セル数だけアーティファクトが増える点は意識しておいてください。組み合わせを絞る判断はGitHub Actionsのマトリックスビルド|組み合わせ展開とinclude・excludeの調整の側で行い、こちらは名前の一意性だけを担保する。そう役割を分けると設定が読みやすくなります。
patternとmerge-multipleで分割した成果物を1つに戻す手順
名前を分けた後、受け取る側で1つのディレクトリへ集めたい場面が来ます。ここで使うのがpatternとmerge-multipleです。pattern: binary-*で対象を絞り、merge-multiple: trueを付けると、指定したpath直下へ中身が並びます。既定のfalseのままなら、アーティファクト名のサブディレクトリが作られます。
actions/upload-artifact/mergeという補助アクションもありますが、こちらは慎重に選んでください。READMEは「多くの場合これが最も効率的な解ではない」と明記し、用途を「UIやREST API経由など、ランナーの外で複数アーティファクトをまとめて落とす必要がある場合に限る」と限定しています。中身は一度ダウンロードして再アップロードする動作なので、ランナー内で使うだけならpatternで足ります。
upload側v7とdownload側v8で1つずれるバージョン対応の読み方
2つのアクションはメジャー番号が揃っていません。「v4で揃えた」記憶のまま最新へ上げると、存在しないタグを指して落ちます。
同時リリースで揃うupload側とdownload側のバージョン対応表
リリース履歴を時系列で並べると、対応関係がはっきりします。
| 公開日 | upload-artifact | download-artifact | 主な変更 |
|---|---|---|---|
| 2025-08-05 | (なし) | v5.0.0 | ID指定時の展開先を統一 |
| 2025-10-24 | v5.0.0 | v6.0.0 | Node 24への予備対応 |
| 2025-12-12 | v6.0.0 | v7.0.0 | Node 24が既定に |
| 2026-02-26 | v7.0.0 | v8.0.0 | 直接転送とESM移行 |
ズレの起点は2025年8月5日のdownload側v5.0.0です。artifact-idsで単一アーティファクトを引いたときの展開先がpath/アーティファクト名/だったのをpath/へ揃える破壊的修正が入り、ここで番号が1つ先行しました。名前で引いている構成、複数IDで引いている構成、既にmerge-multiple: trueを使っている構成は影響を受けません。単一IDで引いてネストされた階層を前提に組んでいた場合だけ、pathへ明示的にサブディレクトリを書き足す必要があります。
v6・v7以降が要求するNode.js 24とランナー2.327.1
2025年12月12日の組(upload側v6.0.0とdownload側v7.0.0)から、実行基盤がnode24になりました。リリースノートは「Actionsランナーの最小バージョン2.327.1を要求する。セルフホストランナーを使っているなら、アップグレード前に更新しておくこと」と警告しています。
GitHubホステッドランナーなら意識せずに済みます。判断が要るのはセルフホストを混ぜている場合で、ランナー側のバージョン確認が先です。ランナー選択そのものの設計はGitHub Actionsのruns-on|ラベル指定の記法と-latest更新・arm64への備えを参照してください。更新の順番を逆にすると、アクションだけ新しくなってジョブが起動段階で落ちます。
archive:falseの直接アップロードと既定errorになったdigest検証
2026年2月26日の組で入った変更は2つあります。1つはupload側のarchive入力です。falseにするとzip化を飛ばして単一ファイルをそのまま送ります。対象は単一ファイルに限られ、globが複数へ解決するとアクションが失敗します。nameは無視され、アップロードしたファイル名がそのままアーティファクト名になる点も押さえてください。
もう1つはdownload側の受け取り方です。v8はContent-Typeヘッダを見てから展開するようになり、zip以外はそのまま置きます。zipを展開せず受け取りたいときはskip-decompress: trueを指定します。
同時に、ダウンロードのハッシュ照合が厳格になりました。以前は不一致でも警告止まりでしたが、v8.0.0からdigest-mismatchの既定値がerrorになり、不一致はワークフローの失敗として扱われます。緩めたい場合の選択肢はignore・info・warnの3つ。なお日本語のアーティファクト名を付けているなら、CJK文字対応が入ったv8.0.1以上を指定してください。
GHESではv4以降が使えずv3.2.2系に留め置かれる移行の制約
GitHub Enterprise Serverはこの流れの外にあります。READMEは「upload-artifact@v4+はGHESで現在サポートされていない。GHESではv3.2.2(Node 24)またはv3.2.2-node20(Node 20)を使う必要がある」と書いています。download側も同様にv3系です。
結果として、GHES環境では同名アーティファクトへの追記という旧挙動がまだ生きています。クラウドとGHESの両方へ同じワークフローを流す構成なら、この差が事故の原因です。GHES側を先に洗い出し、名前の一意性をv3のうちから守っておくほうが移行時の書き換えは減ります。
retention-daysと既定90日が決めるアーティファクトの寿命
アーティファクトは消さない限り時間で積み上がります。設定できる箇所は3層あり、どこが効くかを取り違えると「縮めたつもりで縮んでいない」状態になります。
既定90日とパブリック1〜90日・プライベート1〜400日の上限差
ワークフローが生成したアーティファクトとログは、既定で90日保管された後に自動削除されます。上限はリポジトリの公開設定で分かれ、パブリックリポジトリは1〜90日、プライベートと内部リポジトリは1〜400日の範囲で組織またはリポジトリの設定から変更できます。
見落としやすいのは適用範囲です。公式ドキュメントは「新しいアーティファクトとログファイルにのみ適用され、既存のオブジェクトに遡って適用されることはない」と明記しています。90日から7日へ下げても、昨日までに作られた分は90日目まで残ります。ストレージは時間按分で積み上がる方式なので、切り替え直後の1〜2か月は請求が下がりません。金額の実数と試算の手順はGitHub Actionsの料金|2026年改定後の分単価・無料枠とコスト削減の判断基準にまとめてあります。
retention-daysで縮めるときに効く順序と新規分にしか効かない設定
ワークフロー側のretention-daysは、リポジトリ設定の上限を超えられません。0を指定すると既定に従います。エンタープライズ・組織・リポジトリの3層で上限が絞られていれば、最も厳しい値が勝ちます。
着手の順序は用途別に分けるのが手早い方法です。プルリクエストごとのビルド成果物とテストレポートは1〜7日。ステージング検証用は14日程度。リリースに紐づく配布物だけ既定の90日を残す。この3段階に整理するだけで、日々積み上がる大半が1週間で消えます。長期に配布し続ける必要があるものは、そもそもアーティファクトではなくリリース資産へ移してください。
1ジョブあたり500個の上限とストレージ枠に触れたときの症状
個数にも上限があります。READMEは「個々のジョブ内で作成できるアーティファクトは500個まで」と定めています。テストケースごとにファイルを分けて上げる構成は、この上限に当たる典型です。
厄介なのは検知の遅さです。ストレージ使用量の計算は6〜12時間ごとにしか走らないため、枠を超えた直後は普通に成功し、しばらく経ってからアップロードが失敗し始めます。「昨日まで通っていたのに今朝から落ちる」場合は、まず使用量の画面を見てください。棚卸しはREST APIの一覧取得で古い順に削除するのが確実です。CI基盤の棚卸しや運用の引き取りごと外部に任せたい場合は、保守運用・内製化支援で現状の設定監査から対応しています。
再生成できるかどうかで分けるキャッシュとアーティファクトの使い分け
2つの仕組みは似た顔をしています。置き場所を間違えると、片方は遅くなり、もう片方は請求が膨らみます。
再生成できる依存関係をキャッシュ側へ寄せるという第一の判断軸
判断軸は1つで足ります。消えても同じ手順で作り直せるものはキャッシュ、作り直せないか人が見る必要があるものはアーティファクトです。
この軸を支える根拠は、両者の性質の差です。キャッシュは当たらなくてもジョブが成立する前提の仕組みで、ブランチスコープの制約を受け、容量と未使用期間で自動的に消えます。アーティファクトは実行に紐づいて保持期間まで残り、UIからも落とせます。node_modulesや~/.m2/repositoryはロックファイルから復元できるためキャッシュ側、ビルド済みのバイナリとテストレポートはアーティファクト側。キャッシュのキー設計と復元されない原因の切り分けはGitHub Actionsのキャッシュ|actions/cacheのkey設計と復元されない原因の切り分けで個別に扱っています。
単価と保管方式の違いから見たアーティファクト濫用のコスト構造
両者はストレージの枠も単価も別建てです。アーティファクトの枠はGitHub Packagesと共有され、キャッシュとは別の単価が設定されています。単価が高いのはアーティファクト側です。
最悪の型は、依存パッケージ一式をアーティファクトで次のジョブへ運ぶ構成です。キャッシュなら同じ鍵で1つが使い回されるところ、アーティファクトは実行ごとに新しい実体が作られ、保持期間の日数だけ並列に積み上がります。1日20回動くリポジトリで既定の90日なら、同じ中身が1,800個分の場所を占める計算になります。コンテナイメージも同じ理由でアーティファクトに入れず、レジストリへpushしてタグかダイジェストで参照してください。イメージのビルドとpush先の設計はGitHub ActionsでDockerイメージをビルドする|push先とキャッシュ・マルチアーキの設計にまとめています。
アーティファクトを使わずログとジョブサマリーで足りる場面の線引き
ここも条件を付けて言い切ります。数KBのテキスト結果を人が1度見るだけなら、アーティファクトは過剰です。$GITHUB_STEP_SUMMARYへ書けば実行結果ページに直接表示され、保管も課金も発生しません。lintの件数、テストの成否サマリー、生成された設定値の一覧はこちらで足ります。
アーティファクトを採用する条件は3つに絞れます。後続ジョブがファイルとして読む必要がある場合、リリースへ添付する配布物である場合、失敗の原因追跡にスクリーンショットやHTMLレポートが要る場合。逆に見送ってよいのは、単一ジョブ内で完結する中間ファイル、標準出力で読める短いテキスト、そして依存パッケージのキャッシュ代わりに使おうとしている場合の3つです。配布物を長期に残す用途なら、保持期間の切れないリリース資産のほうが向いています。運用はGitHub Releasesの使い方|リリースノート作成とタグ連携の解説を参照してください。
パーミッション・隠しファイル・権限で起きる3つの受け渡し事故
最後は無音で壊れる3種類。いずれもジョブは緑のまま通り、受け取った先で初めて異常が出ます。
zip化でパーミッションが落ちtarとarchive:falseで守る手順
アーティファクトの保管形式はzipです。この過程でファイルモードが失われ、展開後はディレクトリが755、ファイルが644に揃います。chmod +xした実行ファイルを渡すと、受け取り側で実行ビットが消えています。
回避策は2段階です。まずtar -cvfで1つにまとめ、そのtarファイルをarchive: falseで直接アップロードします。ダウンロード側はnameにtarファイル名を指定して受け取り、手で展開する。この経路ならモードもファイル名の大文字小文字も保たれます。archive入力はupload側v7以降にしかないため、それ以前を使っているならtarをzipに包む形になり、展開が二段になります。
隠しファイルが既定で除外される仕様と開放したときの漏えい経路
ドット始まりのファイルと、ドット始まりのフォルダ配下は、既定でアップロード対象から外れます。機密の巻き込みを防ぐための挙動です。Windowsでは隠し属性だけが付いたファイルは対象外にならず、ドット始まりかどうかで判定される点に差があります。
include-hidden-files: trueで開放すると、この防御が外れます。.env・.npmrc・.git/configが同じディレクトリにあれば、そのままアーティファクトへ入ります。アーティファクトはリポジトリへの読み取り権限を持つ全員がUIから取得できるため、これは実質的な公開です。開放するなら、除外行で危険な対象を名指しで落としてください。認証情報の置き場所そのものの設計はGitHub ActionsのSecrets管理|置き場所の選定と漏えい経路・OIDC移行の判断で扱っています。
他リポジトリや別runからの取得にgithub-tokenが要る条件
download-artifactの既定の可視範囲は、現在のワークフロー実行の中だけです。別の実行や別のリポジトリのアーティファクトは、そのままでは見えません。
越境するには3つの入力を揃えます。対象リポジトリに対してactions:readを持つトークンをgithub-tokenへ、repositoryに所有者とリポジトリ名を、run-idに対象の実行IDを渡す。同一リポジトリの別実行ならrun-idだけで済みますが、別リポジトリでは既定のGITHUB_TOKENでは権限が届かず、PATかGitHub Appのトークンが要ります。ここで権限を広げすぎる設計になりがちなので、GitHub Actionsのpermissions|GITHUB_TOKENの既定権限と最小権限の設計と突き合わせて、読み取りだけに絞った状態を保ってください。
よくある質問
実装の場で繰り返し出る質問を5つ挙げました。
upload-artifactとdownload-artifactのバージョンは揃えるべきですか?
番号を揃える必要はなく、揃えようとすると失敗します。2026年8月25日時点の最新はupload-artifactがv7.0.1、download-artifactがv8.0.1で、番号が1つずれた組が正しい対応です。ズレは2025年8月にdownload側だけが破壊的修正でv5.0.0を出したことに由来します。指定はメジャータグ(@v7と@v8)で書き、リリース履歴の同じ公開日の組を見て対応関係を確認してください。
同じ名前でアーティファクトを2回アップロードできますか?
v4以降はできません。アーティファクトは不変で、同名が既に存在するとアクションが失敗します。どうしても同じ名前を使うならoverwrite: trueを付けますが、これは上書きではなく削除して作り直す動作で、IDが変わります。マトリックスのように複数ジョブが並行して上げる構成では、名前にセルの識別子を付けて分けるのが正しい書き方です。
アーティファクトの保持期間は既定で何日ですか?
既定は90日で、経過後に自動削除されます。retention-daysで短縮でき、上限はパブリックリポジトリが90日、プライベートと内部リポジトリが400日です。組織やエンタープライズ側でより短い上限が設定されていれば、そちらが優先されます。設定変更が効くのは変更後に作られた分だけで、既存のアーティファクトには遡りません。
アーティファクトとキャッシュはどちらを使えばよいですか?
再生成できるかどうかで分けてください。ロックファイルから復元できる依存パッケージはキャッシュ、ビルド済みバイナリやテストレポートのように作り直せないものや人が見るものはアーティファクトです。ストレージの枠も単価も別建てで、アーティファクト側のほうが高く設定されています。依存関係をアーティファクトで運ぶと実行ごとに実体が増えるため、費用面でも不利になります。
別のワークフローで作ったアーティファクトをダウンロードできますか?
できますが、追加の入力が要ります。run-idで対象の実行を指定し、別リポジトリならrepositoryと、対象リポジトリにactions:readを持つgithub-tokenも渡します。既定のGITHUB_TOKENは他リポジトリへ権限が届かないため、PATかGitHub Appのトークンを用意してください。保持期間を過ぎたアーティファクトは削除済みで取得できません。
関連記事
- GitHub Actionsのキャッシュ|actions/cacheのkey設計と復元されない原因の切り分け:依存関係をキャッシュ側へ寄せるときのkey設計はこちらです。
- GitHub Actionsの料金|2026年改定後の分単価・無料枠とコスト削減の判断基準:成果物ストレージの無料枠と超過単価を実額で確認できます。
- GitHub Actionsのマトリックスビルド|組み合わせ展開とinclude・excludeの調整:セル数を絞る判断は名前の一意性とは別の設計です。
- GitHub Actionsのpermissions|GITHUB_TOKENの既定権限と最小権限の設計:越境ダウンロードで広げがちな権限を絞り込めます。
- CI/CDとは?仕組み・パイプライン・導入すべき企業の判断基準を解説:パイプライン全体の設計から見直したい場合の入口です。