Composite Actionは、複数のワークフローステップを1つのアクションにまとめ、呼び出し元のジョブで単一ステップとして実行する仕組みです。JavaScriptやDockerを書かずにaction.ymlだけで共通処理を切り出せる一方、シークレットの扱いやpost処理の書き方には専用の作法があります。この記事ではGitHub公式のメタデータ構文リファレンスと、GitHub Actionsランナー本体の実装ソースを突き合わせて、action.ymlの最小構成、$GITHUB_ACTION_PATHによる同梱スクリプトの参照、後片付け処理の実装手段までを整理します。
まとめ:Composite Actionの要点
- action.ymlにはname、description、runsが必須です。Composite Actionではruns.usingとruns.stepsも必須で、runステップにはshellが必要です。
runs.usingにcompositeを指定し、runを書いたステップには必ずshellを添えます。 - ステップ単位の
ifは使えます。公式メタデータ構文にruns.steps[*].ifが定義されており、ドキュメントの例自体がComposite Actionの失敗時ステップです。「Composite Actionではif条件が使えない」という説明は現行仕様と一致しません。 - Composite Action自身は
postを宣言できません。runs.postはJavaScriptアクション専用です。後片付けは最終ステップにif: always()を付ける形で実装し、その時点のComposite Action全体の結果はgithub.action_statusで判定します。 - 同梱スクリプトの参照には
$GITHUB_ACTION_PATHを使います。相対パスは呼び出し元のワークスペース基準で解決されるため、アクション自身のディレクトリを指す専用の変数が必要です。 secretsコンテキストは参照できません。公式ドキュメントが「セキュリティ上の理由で利用できない」と明記しており、入力として明示的に渡す設計にします。- ネスト上限の公式説明はComposite Actionが10段、Reusable Workflowが10段(GitHub Enterprise Serverのみ4段)です。Reusable Workflowを「4段まで」とする説明はGitHub Enterprise Server向けの記述で、GitHub.comには当てはまりません。
Composite Actionの定義とaction.ymlの最小構成
GitHubのカスタムアクションにはDockerコンテナアクション、JavaScriptアクション、Composite Actionの3種類があります。公式の概念ドキュメントはComposite Actionを「複数のワークフローステップを1つのアクションの中に組み合わせられるもの」と説明しています。ランナー上でステップをそのまま実行するため、ランタイムの同梱もビルド工程も不要です。
runs.usingとshell指定の必須ルール
メタデータ構文の runs.using for composite actions は「この値を 'composite' に設定しなければならない」と規定する必須項目です。もう1つの必須事項が runs.steps[*].shell で、ドキュメントは「run が設定されている場合は必須」と明記しています。ワークフロー本体では既定シェルが効くため省略できますが、Composite Actionでは省略するとaction.ymlの読み込み時点で失敗します。ワークフローからrunステップを移す際は、shellの指定漏れを確認してください。
| キー | Composite Action | JavaScriptアクション |
|---|---|---|
| runs.using | composite(必須) | node24 等のランタイム |
| runs.steps | 必須 | なし |
| runs.steps[*].shell | runがあれば必須 | 該当なし |
| runs.steps[*].if | 利用可 | 該当なし |
| runs.pre / runs.post | 利用不可 | 利用可 |
| secretsコンテキスト | 利用不可 | 利用可 |
inputsとoutputsの定義および呼び出し元との受け渡し
入力は inputs で宣言し、アクション内では inputs.<id> として参照します。出力はJavaScriptアクションと定義方法が異なり、Composite Actionでは outputs.<output_id>.value が必須項目になります。ドキュメントは「steps コンテキストを使ってステップの出力値を出力の value に設定できる」と説明しており、値を返すステップには id を付ける必要があります。
name: 'Setup Node and Install'
description: 'Node.jsのセットアップと依存関係のインストールをまとめる'
inputs:
node-version:
description: 'インストールするNode.jsのバージョン'
required: false
default: '24'
outputs:
cache-hit:
description: 'キャッシュを再利用できたかどうか'
value: ${{ steps.setup.outputs.cache-hit }}
runs:
using: composite
steps:
- id: setup
uses: actions/[email protected]
with:
node-version: ${{ inputs.node-version }}
cache: npm
- run: npm ci
shell: bash
この例は、呼び出し元のリポジトリ直下にpackage.jsonとpackage-lock.jsonがあり、共通アクションを.github/actions/setup-node-and-install/action.ymlに保存する前提です。呼び出し側は通常のアクションと同じく uses と with で指定し、steps.<id>.outputs.<name> で結果を受け取ります。アクションのバージョン指定についてドキュメントは「リリース済みアクションのコミットSHAを使うのが安定性とセキュリティの面で最も安全」としています。サプライチェーン対策としてのSHA固定の運用はSHA Pinningとは?GitHub ActionsをコミットSHAで固定する方法で詳しく扱っています。
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/[email protected]
- id: deps
uses: ./.github/actions/setup-node-and-install
with:
node-version: '24'
- run: echo "cache-hit=${{ steps.deps.outputs.cache-hit }}"
$GITHUB_ACTION_PATHによる同梱スクリプトの参照
Composite Actionにシェルスクリプトを同梱したとき、run: ./scripts/build.sh のような相対パスは意図した場所を指しません。ステップは呼び出し元ジョブのワークスペースを作業ディレクトリとして動くため、相対パスはアクションのディレクトリではなく呼び出し元のリポジトリ基準で解決されるからです。アクションと同じ場所に置いたファイルを指すには、専用のコンテキストと環境変数を使います。
github.action_pathの対応範囲と同梱ファイル参照
公式のコンテキストリファレンスは github.action_path を「アクションが置かれているパス。このプロパティはComposite Actionでのみサポートされる」と定義しています。用途としてはアクションと同じリポジトリにあるファイルへのアクセスが挙げられ、対応する環境変数を使って cd "$GITHUB_ACTION_PATH" のようにディレクトリを移動する例が示されています。メタデータ構文側では、式構文の ${{ github.action_path }} と環境変数の $GITHUB_ACTION_PATH のどちらでも書ける旨が併記されています。
runs:
using: composite
steps:
# 式構文で指定する書き方
- run: '"${{ github.action_path }}/scripts/validate.sh"'
shell: bash
# 環境変数で指定する書き方
- run: '"$GITHUB_ACTION_PATH/scripts/report.sh"'
shell: bash
# アクション直下をPATHに追加する書き方
- run: echo "$GITHUB_ACTION_PATH" >> "$GITHUB_PATH"
shell: bash
スクリプトを同梱する場合は、実行権限を付けた状態でコミットしておく点にも注意します。リポジトリに登録されたファイルモードがそのままランナーへ展開されるため、権限が落ちていると実行時に弾かれます。
action_refとaction_repositoryのrunキーワード制限
同じ github コンテキストでも、github.action_ref(実行中アクションのref)と github.action_repository(所有者とリポジトリ名)には固有の制約があります。ドキュメントは両者について「run キーワードの中では使用しないこと。Composite Actionでこのコンテキストを機能させるには、Composite Actionの env コンテキスト内で参照すること」と注記しています。自分自身のバージョンをログに出したい場合などは、次のように env を経由させます。
runs:
using: composite
steps:
- run: echo "このアクションは $ACTION_REPO@$ACTION_REF として実行されています"
shell: bash
env:
ACTION_REPO: ${{ github.action_repository }}
ACTION_REF: ${{ github.action_ref }}
Composite Actionにおけるpost処理の実装手段
一時ファイルの削除、起動したプロセスの停止、取得したロックの解放といった後片付けをアクション側に持たせたい場面があります。Composite Actionの末尾に条件付きステップを置けば、アクション内の後片付けを実装できます。ただし、これは呼び出し元の次のステップより前に実行され、ジョブ末尾で動くpostフックとは実行タイミングが異なります。
runs.postの対応アクションと実行タイミング
メタデータ構文で runs.pre、runs.post、runs.post-if が定義されているのは「runs for JavaScript actions」の節だけで、Composite Actionの節には対応するキーがありません。runs.post の説明は「main: アクションの完了後、ジョブの最後にスクリプトを実行できる」とされ、実行には using で指定したランタイムが使われます。Composite Actionのメタデータにはruns.postが定義されていないため、独自のpostスクリプトをこのキーで登録することはできません。
なお post-if は「設定されていない場合は always() が既定値」であり、「post-if の中では、ステータスチェック関数はアクション自身のステータスではなくジョブのステータスに対して評価される」と明記されています。また runs.pre にはドキュメント上「ローカルアクションではサポートされない」との注記が付いています。JavaScriptアクションへ切り替える判断をする際は、この2点も前提として押さえておく必要があります。
if: always()による失敗時の後処理ステップ実行
Composite Actionのステップで条件分岐が使えない、という説明が日本語の解説記事には残っていますが、これは現行の仕様と一致しません。メタデータ構文には runs.steps[*].if が「任意項目。条件が満たされない限りステップが実行されないようにするために if 条件を使用できる」として定義されています。公式例でもComposite Actionのステップにfailure()を指定しています。「my backup step は、Composite Actionの直前のステップが失敗したときにのみ実行される」という説明とともに if: ${{ failure() }} の例が示されています。
ランナー側の実装でも裏付けが取れます。Composite Actionの各ステップを処理するハンドラ(v2.337.0 の CompositeActionHandler.cs)は、実行前に always、cancelled、failure、success、hashFiles の各関数を式評価器へ登録しています。つまりワークフロー本体と同じステータスチェック関数が、Composite Action内部でもそのまま使えます。したがって後片付けは、専用の仕組みを探すのではなく最終ステップに if: always() を付けるのが素直な実装です。
runs:
using: composite
steps:
- id: start
run: ./bin/start-server.sh
shell: bash
- run: npm run test:e2e
shell: bash
# 先行ステップの失敗後も後処理を実行対象にする
- name: Cleanup
if: ${{ always() }}
run: '"$GITHUB_ACTION_PATH/scripts/cleanup.sh"'
shell: bash
旧来よく紹介されてきた「主要ステップに continue-on-error: true を付けて最後まで到達させる」という回避策は、失敗そのものが握り潰されてワークフローが成功扱いになるという副作用を伴います。if: always() であれば失敗を失敗のまま伝播させつつ後処理だけを走らせられるため、こちらを選ぶべきです。continue-on-error はComposite Actionのステップでも利用でき、ドキュメントは「ステップが失敗してもアクションが失敗しないようにする」と説明していますが、用途は「失敗を許容したい個別ステップ」に限定するのが適切です。
github.action_statusによるComposite Action全体の結果判定
後片付けの内容を成功時と失敗時で変えたい場合は、github.action_status が使えます。公式のコンテキスト一覧はこれを「Composite Actionにおける、そのComposite Actionの現在の結果」と定義しています。ランナーの実装を見ると、埋め込みステップを実行する直前に「現在のComposite Actionの成否を action_status に設定する」というコメントとともに値を書き込んでおり、ジョブ全体ではなくアクション自身の結果を指すことが確認できます。ジョブがキャンセルされた場合には、キャンセルのコールバックで action_status が更新されたうえで条件が再評価されます。
runs:
using: composite
steps:
- run: ./bin/deploy.sh
shell: bash
- name: Cleanup
if: ${{ always() }}
run: |
if [ "$ACTION_STATUS" = "failure" ]; then
"$GITHUB_ACTION_PATH/scripts/rollback.sh"
elif [ "$ACTION_STATUS" = "success" ]; then
"$GITHUB_ACTION_PATH/scripts/finalize.sh"
fi
shell: bash
env:
ACTION_STATUS: ${{ github.action_status }}
内側でusesしたアクションのpostフックの実行順序
Composite Action自身は post を宣言できませんが、Composite Actionの内側で uses したアクションがpostフックを持っている場合、そのpost処理は失われません。ランナーのアクション解決処理を読むと、ネストされたアクションが post を持つとき、その処理は親であるComposite Actionのステップに紐づく形でスタックへ積まれます。スタックである以上、取り出しは後入れ先出しになり、内側のアクションのpost処理は定義順とは逆順で実行されます。条件には各アクションのクリーンアップ条件(post-if。既定は always())がそのまま引き継がれます。
もう1点、実行の前提として「実際に実行されたステップのpost処理だけを登録する」という判定が入ります。if でスキップされたステップのpostフックは登録されず、スキップされた旨がトレースに残るだけです。actions/cache のようにpost処理でキャッシュを保存するアクションをComposite Actionの内側で条件付きにしている場合、条件が偽になればキャッシュの保存も走らない点に注意してください。
同一リポジトリのアクション参照に使う $/ 構文
Composite Actionの中からさらに別のローカルアクションを呼ぶとき、従来の ./.github/actions/xxx という相対パスには落とし穴があります。この ./ は呼び出し元のワークスペースにチェックアウトされている内容に対して解決されるため、アクションを別リポジトリへ切り出した瞬間に壊れます。
現行のメタデータ構文は、この問題に対する専用の記法として $/ を案内しています。ドキュメントは「Composite Actionと同じリポジトリに格納されたアクションを参照するには $/ 自己リポジトリ参照を使う。これは実行中のコミットにおけるそのリポジトリへ解決されるため、事前にリポジトリをチェックアウトする必要がなく、@{ref} の接尾辞を含めてはならない」と規定しています。ワークフロー構文側の説明でも、$/ は「そのファイルが書かれているリポジトリに対して常に解決され、呼び出した側のリポジトリには解決されない」とされ、アクションの組み合わせにおいて相対パスより信頼できる参照方法だと位置づけられています。
runs:
using: composite
steps:
# 同じリポジトリのアクションを、実行中のコミットで参照する
- uses: $/.github/actions/my-action
# 呼び出し元のワークスペース基準で解決される従来の書き方
- uses: ./.github/actions/my-action
ただしこの記法には適用範囲の制限があります。ドキュメントは「$/ 構文はGitHub Enterprise Serverでは利用できない」と明記しています。オンプレミス環境を併用しているリポジトリでは、従来どおり {owner}/{repo}@{ref} 形式での参照を検討してください。
Reusable Workflowとの使い分けとネスト上限
共通化の手段としてComposite Actionと比較されるのがReusable Workflowです。Composite Actionが1つのジョブの中の複数ステップをまとめるのに対し、Reusable Workflowはジョブそのものを呼び出します。複数ジョブの構成やランナーの指定を共通化したいならReusable Workflow、ジョブ内の手順をまとめたいならComposite Actionという切り分けになります。workflow_call の書き方や入出力の渡し方はReusable Workflows(GitHub Actions)とは?workflow_callでの作成・呼び出しとinputs/secrets/outputsを解説で整理しています。
secretsコンテキストとシークレット受け渡しの差
両者の最も実務的な差がシークレットの扱いです。コンテキストのリファレンスは「secrets コンテキストはセキュリティ上の理由によりComposite Actionでは利用できない。Composite Actionにシークレットを渡したい場合は、入力として明示的に渡す必要がある」と説明しています。Reusable Workflowでは secrets を個別に渡すことも、呼び出し元と同じシークレットを継承させることもできます。
Composite Actionにシークレットを入力として渡す設計にする場合は、渡す値を必要最小限に絞ってください。加えて、ネストしたReusable Workflowについてドキュメントは「チェーン全体を通じて権限は維持または縮小のみが可能で、昇格はできない」と注記しています。チェーンの途中で権限を広げられない前提で、呼び出し元の permissions を設計する必要があります。
Composite ActionとReusable Workflowのネスト上限
ネストの上限は、Composite ActionとReusable Workflowのどちらも公式説明では10段です。ただしComposite Actionはランナー実装に深さ制限の定数9が現れるため、数字の見え方が2通りあります。
Reusable Workflowについて公式ドキュメントは、GitHub.comおよびGitHub Enterprise Cloudでは「最大10段のワークフロー、すなわち最上位の呼び出し元ワークフローと最大9段のReusable Workflowを接続できる」としています。「4段」という数字はGitHub Enterprise Server向けの記述であり、GitHub.comの利用者には当てはまりません。
Composite Actionについて、GitHubの比較表は「1つのワークフローの中で最大10個のComposite Actionをネストできる」と説明しています。実装側ではactions/runner v2.337.0(2026年8月26日公開)の Constants.cs に CompositeActionsMaxDepth = 9 という定数があり、同タグの ActionManager.cs が深さの超過時に「Composite action depth exceeded max depth 9」という例外を送出します。この9は最上位を0として数える深さカウンタの上限値で、0から9までの10段階が公式説明の「最大10個」に対応すると読めます。設計上は10段を上限とし、エラーメッセージに現れる数字が9であることを知っておけば十分です。
| 観点 | Composite Action | Reusable Workflow |
|---|---|---|
| まとめる単位 | ジョブ内のステップ | ジョブ |
| ランナー指定 | 呼び出し元に依存 | 呼び出される側で指定 |
| secretsコンテキスト | 不可(入力で渡す) | 可(継承も可) |
| ネスト上限 | 公式説明は10段 | 10段(GHESは4段) |
| 定義ファイル | action.yml | .github/workflows配下 |
Composite Actionで使えない機能(2026年9月時点)
GitHub Actionsはワークフロー構文側に並行実行の仕組みを備えていますが、これらはComposite Actionの内部では使えません。ワークフロー構文のリファレンスは background について「Composite Actionの内部のステップで background を使用することはできない。Composite Action自体はバックグラウンドステップとして実行できるが、内部でバックグラウンドステップを宣言することはできない」と注記しています。parallel についても「Composite Actionの内部で parallel を使用することはできない」と明記されています。
background はサーバーやデータベースのような長時間プロセスを後続ステップと並走させる指定(ジョブ内で同時実行できるのは最大10個)、parallel はグループ内のステップを同時に走らせて末尾で暗黙に待ち合わせる短縮記法です。どちらもアクションの内側では宣言できないため、並行実行を含む手順を共通化したいなら、呼び出し元のワークフローかReusable Workflowに置く必要があります。「Composite Actionは直列のステップ実行のみ」という理解は現在も有効です。
加えて、Composite Actionは1つのジョブの内側で動くため、matrix や runs-on といったジョブレベルの設定もアクション側では持てません。action.ymlの書式ミスやコンテキストの誤用は実行するまで気づきにくいため、actionlintとは?GitHub Actionsのワークフローを静的解析するLintツールの導入・使い方で触れているactionlintは、呼び出し元ワークフローや参照されたローカルアクションの基本メタデータを検査できます。ただし、Composite Actionのsteps内部は検査対象外のため、コンテキストやシェル指定は別途確認が必要です。
よくある質問
using: composite に指定する値は何ですか?
公式メタデータ構文の runs.using for composite actions は必須項目で、「この値を 'composite' に設定しなければならない」と規定されています。YAMLとしては using: composite、using: 'composite'、using: "composite" のいずれの書き方でも同じ文字列として解釈されます。
Composite Actionのステップでif条件は使えますか?
使えます。メタデータ構文に runs.steps[*].if が定義されており、「条件が満たされない限りステップが実行されないようにするために if 条件を使用できる」と説明されています。ドキュメントの例自体がComposite Actionの直前ステップが失敗したときにのみ動くステップであり、always() や failure() といったステータスチェック関数も利用できます。
Composite Actionからsecretsを直接参照できますか?
できません。コンテキストのリファレンスが「secrets コンテキストはセキュリティ上の理由によりComposite Actionでは利用できない」と明記しています。シークレットを使う場合は、呼び出し元のワークフローで with を使って入力として明示的に渡し、アクション側では通常の入力として受け取る設計にします。
$GITHUB_ACTION_PATHとgithub.action_pathはどう使い分けますか?
指す値は同じで、前者が環境変数、後者が式構文です。メタデータ構文は ${{ github.action_path }}/test/script.sh と $GITHUB_ACTION_PATH/script.sh の両方を並べて示しています。シェルスクリプトの中で展開したい場合や、式の評価結果を直接コマンドに埋め込みたくない場合は環境変数の形を選びます。
Composite Actionは何段までネストできますか?
GitHubの比較表は「1つのワークフローの中で最大10個のComposite Actionをネストできる」と説明しています。ランナー実装の定数 CompositeActionsMaxDepth は9ですが、これは最上位を0として数える深さカウンタの上限値で、v2.337.0時点でこれを超えると「Composite action depth exceeded max depth 9」という例外が発生します。設計上は公式の10段を上限として扱ってください。Reusable Workflowの上限はこれとは別で、GitHub.comでは呼び出し元を含めて最大10段です。
関連記事
- Reusable Workflows(GitHub Actions)とは?workflow_callでの作成・呼び出しとinputs/secrets/outputsを解説
- GitHub Actionsとは?できること・使い方とCI/CD自動化の活用例をわかりやすく解説
- SHA Pinningとは?GitHub ActionsをコミットSHAで固定する方法【Enforce設定・pinact】
- actionlintとは?GitHub Actionsのワークフローを静的解析するLintツールの導入・使い方
- GitHub Actionsでビルド・自動テストを設定する方法|CI/CDワークフローの作り方