再利用可能ワークフローは、on: workflow_call を書いたワークフローを、別のワークフローの「ジョブ」として呼び出す仕組みです。 複数のジョブ・ランナーごとまとめて使い回したいときは再利用可能ワークフロー、ジョブの中の「ステップ」をまとめたいときは composite action を使います。

# 呼び出される側:.github/workflows/reusable-test.yml
on:
  workflow_call:
    inputs:
      node-version:
        type: string
        default: "22"
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-node@v7
        with:
          node-version: ${{ inputs.node-version }}
      - run: npm ci && npm test
# 呼び出す側:.github/workflows/ci.yml
on: [pull_request]
jobs:
  test:
    uses: ./.github/workflows/reusable-test.yml   # steps ではなく jobs の直下に書く
    with:
      node-version: "24"
項目 再利用可能ワークフロー composite action
呼び出す場所 ジョブ(jobs.<id>.uses) ステップ(steps[*].uses)
置き場所 .github/workflows/ 直下の1ファイル action.yml を置いたフォルダかリポジトリ
中身 複数のジョブ(ランナーをジョブごとに選べる) ステップの並び(呼び出し元のランナーで動く)
secrets 使える(渡すか secrets: inherit) secrets コンテキストは使えない。inputs で渡す
入れ子 呼び出し元を含めて10段まで 1つのワークフローで10個まで

確認環境:この記事の YAML は actionlint 1.7.12(GitHub リリースのバイナリ)と check-jsonschema 0.38.2(SchemaStore のスキーマ)で検査し、検出されたエラー文をそのまま載せています。入れ子の上限・権限・secrets の決まりは GitHub Docs と GitHub Changelog(2025年11月6日)で確かめています。アクションの版(actions/checkout v7.0.1・actions/setup-node v7.1.0)は git ls-remote でタグを確かめました(確認日 2026年10月13日)。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「GitHub Actions再利用可能ワークフロー|compositeとの違い」

再利用可能ワークフローの書き方

呼び出される側(workflow_call)

on.workflow_call の下に、受け取る値(inputs)・秘密情報(secrets)・返す値(outputs)を書きます。

# .github/workflows/reusable-test.yml
name: reusable-test

on:
  workflow_call:
    inputs:
      node-version:
        description: 使う Node.js の版
        type: string
        default: "22"
      run-e2e:
        type: boolean
        default: false
      shard-count:
        type: number
        default: 1
    secrets:
      NPM_TOKEN:
        required: false
    outputs:
      coverage:
        description: 行カバレッジ(%)
        value: ${{ jobs.test.outputs.coverage }}

permissions:
  contents: read

jobs:
  test:
    runs-on: ubuntu-latest
    outputs:
      coverage: ${{ steps.cov.outputs.pct }}
    steps:
      - uses: actions/checkout@v7
      - uses: ./.github/actions/setup-node-deps
        with:
          node-version: ${{ inputs.node-version }}
          npm-token: ${{ secrets.NPM_TOKEN }}
      - run: npm test -- --coverage
      - id: cov
        run: echo "pct=87.5" >> "$GITHUB_OUTPUT"
      - if: ${{ inputs.run-e2e }}
        run: npm run e2e -- --shard-count=${{ inputs.shard-count }}
キー 書けるもの 注意
inputs.<名前>.type string・number・boolean 必須。呼び出し側の値の型が合わないとエラー
inputs.<名前>.required true / false default と組み合わせる
secrets.<名前>.required true / false required: true は「渡されたか」だけを見る(空の値でも通る)
outputs.<名前>.value ${{ jobs.<ジョブ>.outputs.<名前> }} ジョブの outputs を経由する。ステップの outputs は直接書けない

ファイルは .github/workflows/ の直下に置きます。 GitHub Docs には「Subdirectories of the workflows directory are not supported.」とあります。

呼び出す側

# .github/workflows/ci.yml
name: ci

on:
  pull_request:
  push:
    branches: [main]

permissions:
  contents: read

jobs:
  test:
    strategy:
      fail-fast: false
      matrix:
        node: ["22", "24"]
    uses: ./.github/workflows/reusable-test.yml
    with:
      node-version: ${{ matrix.node }}
      run-e2e: ${{ github.event_name == 'push' }}
    secrets:
      NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

  report:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - run: echo "coverage=${{ needs.test.outputs.coverage }}"

呼び出すジョブには runs-on も steps も書きません。 GitHub Docs で呼び出すジョブに書けるとされているキーは次の通りです。

キー 使いどころ
name 表示名
uses 呼び出すワークフロー
with inputs に渡す値
secrets secrets に渡す値、または inherit
strategy matrix で複数回呼ぶ
needs / if 順番と条件
concurrency 同時実行の制御
permissions 呼び出し先に渡す GITHUB_TOKEN の権限
cache-mode キャッシュの読み書きの範囲(read・write・write-only・none)

matrix で呼んだときの outputs は、値を設定した最後の成功した実行の値になります(GitHub Docs)。matrix の行ごとの値を集めたいときは、行ごとに名前を変えた artifact に書き出す方法があります。

uses の書き方

書き方 意味
./.github/workflows/test.yml 同じリポジトリ・同じコミットのファイル
octo-org/shared/.github/workflows/test.yml@v1 別のリポジトリ(タグ)
octo-org/shared/.github/workflows/test.yml@0123abcd...(40文字) 別のリポジトリ(コミット SHA)。GitHub Docs はこの形を勧めている
$/.github/workflows/test.yml 同じリポジトリの新しい書き方。@ref は付けない。GitHub Enterprise Server では使えない

uses には ${{ }} の式を書けません。 GitHub Docs には「You cannot use contexts or expressions in this keyword.」とあります。

secrets の渡し方と secrets: inherit

書き方 渡るもの 使える範囲
secrets: { NPM_TOKEN: ${{ secrets.NPM_TOKEN }} } 書いたものだけ どこでも
secrets: inherit 呼び出し元が見えるすべての secrets 同じ組織、または同じ Enterprise の中

secrets は、直接呼び出したワークフローにだけ渡ります。 GitHub Docs には「Secrets are only passed to directly called workflow.」とあり、A → B → C と呼ぶとき、C で使う secrets は B が改めて渡す必要があります。

環境(environment)の secrets は、呼び出し側からは渡せません。 呼び出すジョブには environment を書けず、呼び出される側のジョブに environment を書いてその secrets を読みます。同じ名前の secrets があるときは environment の secrets が使われます。

env も引き継がれません。GitHub Docs の決まりです。

渡したいもの 渡り方
呼び出し元のワークフローの env 渡らない。with に書くと actionlint は context "env" is not allowed here
呼び出される側の env 呼び出し元からは見えない
組織・リポジトリ・環境の変数(vars) 両方で ${{ vars.NAME }} として読める
呼び出される側の結果 outputs で返す

入れ子(ネスト)と上限

再利用可能ワークフローは、呼び出し元を含めて10段までつなげられます。 2025年11月6日の GitHub Changelog で、4段から10段、呼び出せる数が20から50に引き上げられました。

上限 github.com 出典
入れ子の段数 10段(呼び出し元 + 再利用可能ワークフロー9段) GitHub Docs
1つのワークフローファイルから呼べる種類 50(入れ子の先も数える) GitHub Docs
ループ 不可(「Loops in the workflow tree are not permitted.」) GitHub Docs
composite action の入れ子 1つのワークフローで10個まで GitHub Docs

GitHub Enterprise Server では版によって上限が異なるので、使っている版の Docs を見ます。

入れ子のコピペ例:ci → release → deploy

# ci.yml の jobs に足す
  release:
    if: github.ref == 'refs/heads/main'
    needs: test
    permissions:
      contents: read
      id-token: write
    uses: ./.github/workflows/reusable-release.yml
    with:
      environment: production
    secrets: inherit
# .github/workflows/reusable-release.yml(2段目)
name: reusable-release

on:
  workflow_call:
    inputs:
      environment:
        type: string
        required: true

jobs:
  deploy:
    permissions:
      contents: read
      id-token: write
    uses: ./.github/workflows/reusable-deploy.yml
    with:
      environment: ${{ inputs.environment }}
    secrets:
      SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}   # 3段目へは改めて渡す
# .github/workflows/reusable-deploy.yml(3段目)
name: reusable-deploy

on:
  workflow_call:
    inputs:
      environment:
        type: string
        required: true
    secrets:
      SLACK_WEBHOOK_URL:
        required: true
    outputs:
      url:
        value: ${{ jobs.deploy.outputs.url }}

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: ${{ inputs.environment }}
    permissions:
      contents: read
      id-token: write
    outputs:
      url: ${{ steps.deploy.outputs.url }}
    steps:
      - uses: actions/checkout@v7
      - id: deploy
        run: echo "url=https://example.com" >> "$GITHUB_OUTPUT"
      - name: 通知
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
        run: |
          curl -fsS -X POST -H 'Content-Type: application/json' \
            -d "{\"text\":\"deployed ${{ inputs.environment }}\"}" "$SLACK_WEBHOOK_URL"

この記事の4つのワークフローと composite action を actionlint 1.7.12 で検査した結果です。

actionlint
echo $?
# 0(指摘なし)

権限(permissions)の受け渡し

呼び出される側は、呼び出し元から受け取った GITHUB_TOKEN の権限を「同じか、狭く」しかできません。 GitHub Docs の決まりです。

状況 結果
呼び出すジョブに permissions が無い 既定の GITHUB_TOKEN の権限が渡る(ワークフローの最上位に書いた permissions があればそれ)
呼び出される側で同じか狭い権限を書く その権限になる
呼び出される側で広い権限を書く 実行時にエラー
A → B → C の入れ子 段を下るほど同じか狭くなる。A が packages: read なら B・C は packages: write にできない

広い権限を求めたときのエラーは、次の形です(実際に報告された文面)。

The nested job 'message-check' is requesting 'pull-requests: read', but is only allowed 'pull-requests: none'.

直し方は、呼び出す側のジョブで先に権限を与えることです。 上の入れ子の例で ci.yml の release ジョブに id-token: write を書いているのは、3段目で OIDC のトークンを取るためです。なお、この「広げられない」誤りは actionlint 1.7.12 では検出されませんでした(3段目を contents: write にしても指摘なし)。

OIDC で AWS に入る設定は、関連記事「GitHub ActionsからOIDCでAWSへ|IAMロールの信頼ポリシー」で扱っています。再利用可能ワークフローから OIDC を使うと、トークンの job_workflow_ref に呼び出された側のワークフローのパスと ref が入ります。

composite action の書き方

composite action は、複数のステップを1つのステップとしてまとめたものです。 呼び出し元のジョブと同じランナーで動き、チェックアウトしたファイルや環境もそのまま使えます。

# .github/actions/setup-node-deps/action.yml
name: setup-node-deps
description: Node.js を入れて npm ci する
inputs:
  node-version:
    description: Node.js の版
    required: false
    default: "22"
  npm-token:
    description: private パッケージ用のトークン
    required: false
    default: ""
outputs:
  cache-hit:
    description: キャッシュが当たったか
    value: ${{ steps.node.outputs.cache-hit }}
runs:
  using: composite
  steps:
    - id: node
      uses: actions/setup-node@v7
      with:
        node-version: ${{ inputs.node-version }}
        cache: npm
    - run: npm ci
      shell: bash
      env:
        NODE_AUTH_TOKEN: ${{ inputs.npm-token }}
# 呼び出す側(ステップとして使う)
    steps:
      - uses: actions/checkout@v7          # ローカルの action を使う前にチェックアウトが要る
      - id: deps
        uses: ./.github/actions/setup-node-deps
        with:
          node-version: "24"
          npm-token: ${{ secrets.NPM_TOKEN }}   # secrets は inputs で渡す
      - run: echo "cache-hit=${{ steps.deps.outputs.cache-hit }}"
決まり 内容
runs.using composite
run のステップ shell が必須(GitHub Docs「Required if run is set.」)
secrets 使えない。GitHub Docs「The secrets context is not available for composite actions due to security reasons.」
inputs ${{ inputs.<名前> }} で読む。INPUT_<名前> の環境変数は自動では作られない
outputs value に ${{ steps.<id>.outputs.<名前> }} を書く
書けないキー timeout-minutes など(check-jsonschema で Additional properties are not allowed ('timeout-minutes' was unexpected))

actionlint は action.yml の中身を検査しません。 action.yml を渡すと "jobs" section is missing in workflow となりました。呼び出し側の inputs の誤りは actionlint が見つけ、action.yml の書き方は check-jsonschema の --builtin-schema vendor.github-actions で検査できました。

check-jsonschema --builtin-schema vendor.github-actions .github/actions/*/action.yml
check-jsonschema --builtin-schema vendor.github-workflows .github/workflows/*.yml

再利用可能ワークフローと composite action の比較表

GitHub Docs の比較をもとに、書き方の違いを足した表です。

比べる点 再利用可能ワークフロー composite action
呼び出し jobs.<id>.uses steps[*].uses
ファイル .github/workflows/*.yml(サブフォルダ不可) <フォルダ>/action.yml
ジョブ・ランナー 複数のジョブ。ジョブごとに runs-on ジョブを持たない。呼び出し元のランナー
ログ ジョブ・ステップごとに表示 1つのステップとして表示
secrets 渡せる・inherit できる inputs で渡す
environment(承認・環境 secrets) 呼び出される側のジョブに書ける 書けない(呼び出し元のジョブで指定)
permissions ジョブごとに書ける(広げられない) 書けない(呼び出し元のジョブの権限)
結果の返し方 outputs(ジョブの outputs 経由) outputs(ステップの outputs 経由)
入れ子 10段まで 1つのワークフローで10個まで
Marketplace 公開できない 公開できる
向いている用途 ビルド→テスト→デプロイの流れを組織で共通化 セットアップ・キャッシュ・通知など数ステップの部品

迷ったら「ランナーやジョブを分けたいか」「secrets・environment をまとめて扱いたいか」で決めます。 どちらも当てはまらない数ステップの部品は composite action が軽く書けます。

actionlint で検出できた誤り・できなかった誤り

actionlint 1.7.12 で、わざと誤りを入れて検査した結果です。

誤り actionlint の出力(原文)
呼び出すジョブに runs-on when a reusable workflow is called with "uses", "runs-on" is not available. only following keys are allowed: "name", "uses", "with", "secrets", "needs", "if", and "permissions" in job "a"
呼び出すジョブに steps ... "steps" is not available. ...
呼び出すジョブに environment ... "environment" is not available. ...
定義していない input input "python-version" is not defined in "./.github/workflows/reusable-test.yml" reusable workflow. defined inputs are "node-version", "run-e2e", "shard-count"
必須の input を渡さない input "env-name" is required by "./.github/workflows/r2.yml" reusable workflow
number の input に文字列 input "shard-count" is typed as number by reusable workflow "./.github/workflows/reusable-test.yml". string value cannot be assigned
定義していない secret を渡す secret "OTHER" is not defined in "./.github/workflows/reusable-test.yml" reusable workflow. defined secret is "NPM_TOKEN"
返していない outputs を読む property "cov" is not defined in object type {}
outputs.value にステップの値 context "steps" is not allowed here. available contexts are "github", "inputs", "jobs", "vars".
with で env を使う context "env" is not allowed here. available contexts are "github", "inputs", "matrix", "needs", "strategy", "vars".
uses に式 context "github" is not allowed here. no context is available here.
別リポジトリの uses に @ref が無い reusable workflow call "octo-org/shared/.github/workflows/build.yml" at "uses" is not following the format "owner/repo/path/to/workflow.yml@ref" nor "./path/to/workflow.yml".
composite action の必須 input が無い missing input "token" which is required by action "bad-comp" defined at "./.github/actions/bad-comp". all required inputs are "token"

検出されなかったものも記録しておきます。GitHub 上で実行すると失敗するか、意図と違う動きになるものです。

誤り actionlint 1.7.12
ステップの uses に再利用可能ワークフローを書く 指摘なし
.github/workflows/sub/ に置いたワークフローを呼ぶ 指摘なし
string の input に数値 24、boolean の input に "yes" 指摘なし
呼び出される側で権限を広げる 指摘なし
$/.github/workflows/... の書き方 書式違反として誤って指摘される
呼び出すジョブの cache-mode unexpected key "cache-mode" for "job" section と誤って指摘される
呼び出すジョブの strategy・concurrency 指摘なし(正しく通る)

$/ と cache-mode は GitHub Docs に載っている新しい書き方ですが、actionlint 1.7.12 ではエラーになります。 使う場合は、actionlint の -ignore で該当のメッセージを除くか、従来の ./.github/workflows/... で書きます。

actionlint -ignore 'unexpected key "cache-mode"'

よくあるエラーと直し方

症状 原因 直し方
呼び出したワークフローが見つからない @ref の誤り、private リポジトリのアクセス設定 呼び出される側のリポジトリの Settings → Actions → Access で、呼び出し元のリポジトリを許可する
secrets が空になる 入れ子の2段目で渡し直していない/environment の secrets を呼び出し元で読もうとした 各段で secrets: を書く。environment は呼び出される側のジョブに書く
is requesting ..., but is only allowed ... 呼び出される側が広い権限を求めた 呼び出すジョブの permissions で先に与える
env の値が使えない env は引き継がれない with で渡すか vars を使う
名前を変えたら呼び出しが失敗 GitHub はリダイレクトしない(GitHub Docs) uses のパスを新しい名前に直す
呼び出し元ごとキャンセルされる 呼び出し元と呼び出される側で同じ concurrency.group に cancel-in-progress: true 呼び出される側の ${{ github.workflow }} は呼び出し元の名前になるので、グループ名を分ける

public のリポジトリからは public の再利用可能ワークフローしか呼べません。 private のリポジトリからは private と public の両方を呼べます。GitHub がホストするランナーの割り当てと課金は、呼び出し元のリポジトリで決まります。

よくある質問

Q. 呼び出した側のファイルを更新したのに、再実行で前の版が動きます。 A. GitHub Docs によると、「失敗したジョブを再実行」は最初の実行と同じコミット SHA の再利用可能ワークフローを使います。「すべてのジョブを再実行」は uses の ref が指す最新の版を使います。

Q. 別リポジトリのワークフローは、タグとコミット SHA のどちらで指定しますか? A. GitHub Docs は、安定性と安全性の理由からコミット SHA を勧めています。タグは後から付け替えられるためです。SHA で固定したときの更新の自動化は、関連記事「Dependabot・Renovate設定|目的別コピペ設定集と比較表」で扱っています。

Q. 呼び出される側で github コンテキストは何を指しますか? A. GitHub Docs では、呼び出される側の github コンテキストは呼び出し元のワークフローのものになります(github.workflow が呼び出し元の名前になるのもこのためです)。

GitHub Actions の基本は関連記事「CI/CDとは|GitHub Actionsで最初のパイプラインを作るまで」、キャッシュと matrix は「GitHub Actionsのキャッシュとmatrix|コピペ用YAMLとキー設計」で扱っています。

まとめ

  • ジョブごと使い回すなら再利用可能ワークフロー(on: workflow_call → jobs.<id>.uses)、ステップをまとめるなら composite action
  • inputs は string・number・boolean。outputs はジョブの outputs を経由して返す
  • secrets: inherit は同じ組織・Enterprise の中だけ。secrets は直接呼んだ先にしか渡らない
  • env は引き継がれない。with か vars
  • 入れ子は10段・50種類まで(2025年11月に4段・20から引き上げ)
  • 権限は呼び出し元で与え、呼び出される側は狭めるだけ
  • actionlint は inputs・secrets・outputs の誤りを見つけるが、権限の広げすぎ・サブフォルダ・action.yml の中身は見ない。$/ と cache-mode は誤って指摘される

参考・出典

確認日はいずれも 2026年10月13日です。

  • GitHub Docs「Reuse workflows」:https://docs.github.com/en/actions/how-tos/reuse-automations/reuse-workflows
  • GitHub Docs「Reusable workflows reference」:https://docs.github.com/en/actions/reference/workflows-and-actions/reusing-workflow-configurations
  • GitHub Docs「Reusing workflow configurations」:https://docs.github.com/en/actions/concepts/workflows-and-actions/reusing-workflow-configurations
  • GitHub Docs「Metadata syntax reference」:https://docs.github.com/en/actions/reference/workflows-and-actions/metadata-syntax
  • GitHub Docs「Contexts reference」:https://docs.github.com/en/actions/reference/workflows-and-actions/contexts
  • GitHub Changelog「New releases for GitHub Actions – November 2025」:https://github.blog/changelog/2025-11-06-new-releases-for-github-actions-november-2025
  • rhysd/actionlint v1.7.12:https://github.com/rhysd/actionlint
  • check-jsonschema:https://github.com/python-jsonschema/check-jsonschema
  • Eclipse platform-dev メーリングリスト(権限エラーの文面):https://www.eclipse.org/lists/platform-dev/msg03876.html

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「GitHub Actions再利用可能ワークフロー|compositeとの違い」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?