はじめに
ども!先輩社員から Azure Static Web Apps のビルドの相談を受けて、そういえばそのブログを書いたことないなって「はっ!」となった龍ちゃんです。
今まで、過去にセットアップしたものを使いまわしていたんですけど、身近にありすぎて忘れていました。そんなわけでまとめていきます。Azure Static Web Apps はよく使用します。今回の記事をふんだんに使ったブログは「Azure Static Web Apps: x-ms-client-principal で安全なロールベース制御」です。
それでは本題に入ります。Azure Static Web Apps(以下、SWA)を使っていて、「デプロイに時間がかかるな…」と感じたことはありませんか?
Azure Portal から SWA を作成すると、GitHub Actions のワークフローファイルが自動生成されます。このデフォルト設定では、Microsoft の Oryx ビルドシステムが使用され、プロジェクトを自動的に検出してビルドしてくれます。
しかし、このデフォルト設定には以下のような課題があります:
- ❌ 毎回依存関係のフルインストールが発生(キャッシュなし)
 - ❌ テストや Linter の実行ができない
 - ❌ ビルドプロセスのカスタマイズが困難
 
本記事では、GitHub Actions 上でカスタムビルドを実装し、デプロイ時間を短縮する方法を解説します。
Oryx ビルドシステムとは
Oryx の概要
Oryx(オリックス)は、Microsoft が開発したオープンソースのビルドシステムで、ソースコードを自動的に実行可能なアーティファクトにコンパイルします。
公式リポジトリ: https://github.com/microsoft/Oryx
Azure Static Web Apps、Azure App Service、Azure Functions などで利用されています。
自動検出の仕組み
Oryx は以下のように動作します:
- リポジトリの内容を分析
 - 使用されているプログラミング言語・フレームワークを検出
 - 適切なビルドコマンドを自動実行
 
具体例(Node.js の場合)
検出内容                    → 実行されるコマンド
----------------------------------------------------
package.json が存在       → npm install
                          → npm run build または npm run build:azureデフォルトワークフローの動作
Azure Portal から SWA を作成すると、以下のようなワークフローファイルが自動生成されます:
name: Azure Static Web Apps CI/CD
on:
  push:
    branches:
      - main
  pull_request:
    types: [opened, synchronize, reopened, closed]
    branches:
      - main
jobs:
  build_and_deploy_job:
    if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
    runs-on: ubuntu-latest
    name: Build and Deploy Job
    steps:
      - uses: actions/checkout@v3
        with:
          submodules: true
          lfs: false
      - name: Build And Deploy
        id: builddeploy
        uses: Azure/static-web-apps-deploy@v1
        with:
          azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }}
          action: "upload"
          app_location: "/" # アプリのソースコードパス
          api_location: "" # APIのソースコードパス(オプション)
          output_location: "dist" # ビルド済みアプリのディレクトリ(オプション)このワークフローの特徴:
- ✅ シンプルで設定が簡単
 - ✅ Oryx が自動的にビルド設定を検出
 - ❌ 毎回依存関係のインストールが発生(キャッシュなし)
 - ❌ ビルド時間が長い
 - ❌ テストの実行ができない
 - ❌ ビルドプロセスのカスタマイズが困難
 
カスタムビルドで得られるメリット
GitHub Actions 上でビルドを実行することで、以下のようなメリットが得られます。
1. 依存関係のキャッシュ
actions/setup-node@v6 の組み込みキャッシュ機能を使用することで、依存関係のダウンロード時間を大幅に短縮できます。
- uses: actions/setup-node@v6
  with:
    node-version: "20"
    cache: "npm" # npm, yarn, pnpm をサポート
    cache-dependency-path: "package-lock.json"2025 年 11 月時点の推奨バージョン: actions/setup-node@v6 が最新版です。v6 では Node.js 24 ランタイムへのアップグレードやセキュリティ強化が行われています。v6 でも v4 と同様に cache: "npm" でキャッシングが有効化されます。基本的な使い方は互換性があるため、v4 からの移行は容易です。
キャッシュの仕組み
package-lock.jsonのハッシュ値をキーとして使用- ファイルが変更されない限り、同じキャッシュが再利用される
 ~/.npmディレクトリがキャッシュされる
2. テスト・Linter の統合
ビルドプロセスに、テストや静的解析(Linter)を組み込むことができます。
- name: Run tests
  run: npm test
- name: Run linter
  run: npm run lintこれにより、品質の低いコードが本番環境にデプロイされるのを防げます。
3. ビルドプロセスの完全制御
複雑なビルド要件(環境変数の設定、複数ステップのビルド、モノレポ対応など)に柔軟に対応できます。
4. デプロイの高速化
依存関係のキャッシュにより、2 回目以降のデプロイが大幅に高速化されます。
実装手順
Step 1: ワークフローファイルの作成
.github/workflows/frontend-deploy.yml を作成します。
name: Frontend SWA Deploy
on:
  push:
    branches:
      - main
  workflow_dispatch:
jobs:
  build-and-deploy:
    runs-on: ubuntu-22.04
    environment: production
    steps:
      # 1. リポジトリをチェックアウト
      - name: Checkout repository
        uses: actions/checkout@v4
      # 2. Node.js のセットアップ(キャッシュあり)
      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version: "20"
          cache: "npm"
          cache-dependency-path: "application/frontend/package-lock.json"
      # 3. 依存関係のインストール
      - name: Install dependencies
        run: |
          cd application/frontend
          npm ci
      # 4. テストとLinterの実行(オプション)
      - name: Run tests
        run: |
          cd application/frontend
          npm test
      - name: Run linter
        run: |
          cd application/frontend
          npm run lint
      # 5. ビルド実行
      - name: Build frontend
        run: |
          cd application/frontend
          npm run build
      # 6. Azure Static Web Apps へデプロイ
      - name: Deploy to Azure Static Web Apps
        uses: Azure/static-web-apps-deploy@v1
        with:
          azure_static_web_apps_api_token: ${{ secrets.AZURE_SWA_DEPLOY_TOKEN }}
          repo_token: ${{ secrets.GITHUB_TOKEN }}
          action: "upload"
          app_location: "./application/frontend/out"
          output_location: ""
          skip_app_build: true # 重要: Oryx ビルドをスキップStep 2: デプロイトークンの取得
- Azure Portal にアクセス
 - 対象の Static Web Apps リソースを開く
 - 左メニューから「管理」を選択
 - 「デプロイトークン」をコピー
 
Step 3: GitHub Secrets の設定
- GitHub リポジトリの Settings → Secrets and variables → Actions
 - New repository secret をクリック
 - 以下を設定:
- Name: 
AZURE_SWA_DEPLOY_TOKEN - Secret: 手順 2 でコピーしたトークンを貼り付け
 
 - Name: 
 - Add secret をクリック
 
セキュリティのベストプラクティス
デプロイトークンを安全に管理するための推奨事項:
1. 環境レベルのシークレット管理
リポジトリレベルではなく、GitHub 環境(staging、production)ごとにトークンを管理することを推奨します。
- Settings → Environments → New environment で環境を作成
 - 環境ごとに異なるトークンを設定
 
これにより、環境ごとのアクセス制御が可能になり、誤ったデプロイを防げます。
2. 定期的なローテーション
トークンは定期的に再生成することを推奨します。
- Azure Portal → Static Web Apps → 管理 → デプロイトークンの再生成
 - GitHub Secrets を更新
 
3. 漏洩時の対応
トークンが漏洩した場合は、即座に再生成してください。
- Azure Portal でトークンを再生成
 - GitHub Secrets を更新すれば、次回デプロイから新しいトークンが使用されます
 
重要な設定ポイント
skip_app_build: true
この設定により、Oryx によるビルドをスキップし、既にビルド済みのファイルをそのままデプロイします。
skip_app_build: trueapp_location の指定
skip_app_build: true を使用する場合、ビルド済みファイルのディレクトリを指定します。
app_location: "./application/frontend/out" # Next.js の場合output_location は空文字列
skip_app_build: true と併用する場合は空文字列に設定します。
output_location: ""npm ci の使用
npm install ではなく、npm ci を使用することを強く推奨します。
# ❌ 避けるべき
- run: npm install
# ✅ 推奨
- run: npm ci理由:
npm ciはpackage-lock.jsonを厳密に再現- より高速で、CI/CD 環境に最適化されている
 node_modulesを削除してからインストールするため、クリーンな環境が保証される
モノレポ構成での最適化
モノレポの場合、変更があったディレクトリのみビルドするように paths フィルタを設定できます。
on:
  push:
    branches:
      - main
    paths:
      - "application/frontend/**"
      - ".github/workflows/frontend-deploy.yml"メリット:
- フロントエンドの変更時のみワークフローが実行される
 - 無駄なビルドを削減
 - GitHub Actions の実行時間を節約
 
補足: SWA CLI を使用したデプロイ方法
公式の Azure/static-web-apps-deploy@v1 アクションを使わず、SWA CLI を直接使用する方法もあります。
実装例
- name: Install SWA CLI
  run: npm install -g @azure/static-web-apps-cli
- name: Deploy with SWA CLI
  run: |
    swa deploy ./application/frontend/out \
      --deployment-token ${{ secrets.AZURE_SWA_DEPLOY_TOKEN }} \
      --env productionメリット・デメリット
メリット:
- ✅ GitHub Actions のキャッシュ機能を利用できる
 - ✅ ローカル開発でも同じ CLI を使用できる(開発体験の統一)
 - ✅ デプロイプロセスの細かい制御が可能
 
デメリット:
- ❌ SWA CLI への深い理解が必要(学習コスト)
 - ❌ 公式アクションに比べて設定が複雑
 - ❌ CLI のバージョン管理が必要
 
推奨の使い分け
- 公式アクション(
Azure/static-web-apps-deploy@v1)を推奨- カスタマイズ箇所が少なく、保守性が高い
 - 本記事で紹介した 
skip_app_build: trueパターンで十分高速 
 - SWA CLI が向いているケース
- ローカルで既に SWA CLI を使って開発している
 - デプロイプロセスに特殊な要件がある
 - CLI の細かい制御機能が必要
 
 
結論: ほとんどのケースでは、公式アクションをアップローダーとして利用する方法で十分です。
認証方法の選択:デプロイトークン vs OIDC
デプロイトークン方式(推奨)
特徴
- ✅ シンプルで設定が簡単
 - ✅ Azure Static Web Apps の標準的な認証方法
 - ✅ 安定性が高い
 - ❌ トークンの管理が必要
 
使い方
- uses: Azure/static-web-apps-deploy@v1
  with:
    azure_static_web_apps_api_token: ${{ secrets.AZURE_SWA_DEPLOY_TOKEN }}OIDC Federated Credentials(2025年10月時点)
現状
Azure Static Web Apps は、デプロイ認証において OIDC(OpenID Connect)をネイティブサポートしていません(2025 年 1 月時点)。
補足: ユーザー認証用の OIDC(Auth0、Azure AD B2C など)は Standard プランで利用可能です。ここで述べているのは、GitHub Actions からのデプロイ時の認証に関する制限です。
他の Azure サービス(App Service、Container Instances など)では、デプロイ認証における OIDC がサポートされていますが、Static Web Apps では未対応です。
参考: GitHub Issue #1304 – Add Federated Credentials support
回避策の存在とリスク
OIDC トークンを使って Azure CLI で認証し、デプロイトークンを動的に取得する方法は存在しますが:
- ⚠️ トークンのマスキング設定ミスによるリークリスク
 - ⚠️ 設定が複雑
 - ⚠️ 現時点では推奨されない
 
推奨事項
2025 年 1 月時点では、デプロイトークン方式が最も安全で信頼性の高い方法です。
OIDC 対応については、コミュニティから強く要望されており、将来的にサポートされる可能性は高いですが、現時点ではまだ実装されていません。
トラブルシューティング
問題 1: キャッシュが効かない
症状
2 回目以降のビルドでも npm ci に時間がかかる
原因
cache-dependency-path が指定されていない、または間違っている
解決策
# ❌ 間違った設定
- uses: actions/setup-node@v4
  with:
    cache: "npm"
    # cache-dependency-path が指定されていない
# ✅ 正しい設定
- uses: actions/setup-node@v4
  with:
    cache: "npm"
    cache-dependency-path: "package-lock.json"モノレポの場合は、正しいパスを指定します:
cache-dependency-path: "application/frontend/package-lock.json"問題 2: デプロイが失敗する
症状
Error: No such file or directory原因
skip_app_build: true を使用しているのに、app_location が正しくない
解決策
# ❌ 間違った設定
app_location: "/"  # ソースコードのパス
skip_app_build: true
# ✅ 正しい設定
app_location: "./application/frontend/out"  # ビルド済みディレクトリ
skip_app_build: true
output_location: ""問題 3: ビルドコマンドが見つからない
症状
npm run build: command not found原因
package.json に build スクリプトが定義されていない
解決策
package.json に build スクリプトを追加します:
{
  "scripts": {
    "build": "next build"
  }
}または、ワークフローで直接コマンドを指定します:
- name: Build frontend
  run: next build問題 4: Actions のキャッシュサイズ超過
症状
Warning: Cache size exceeded limit原因
node_modules が大きすぎる
解決策
setup-node のキャッシュは ~/.npm をキャッシュするため、通常は問題ありません。
もし問題が発生する場合は、不要な devDependencies を削除するか、キャッシュを無効化します。キャッシュを無効化すると、カスタムビルドを組む意味が大幅に減ってしまいます。おそらくですが、この事象が頻発する場合はOryxのビルドも失敗するんちゃうかな?って思っとります。
問題 5: ビルドタイムアウト
症状
Error: Build timed out after 15 minutes原因
Azure Static Web Apps のビルドには 15 分の制限があります
解決策
カスタムビルド(本記事の方法)に移行することで、この制限を回避できます。GitHub Actions 側でビルドを行うため、Azure SWA 側のタイムアウトは影響しません。
まとめ
今回は、Azure Static Web Apps のデプロイを高速化するための、GitHub Actions カスタムビルドの実装方法をご紹介しました。
カスタムビルドを導入すべきケース
小規模プロジェクト・個人開発
- デフォルトの Oryx ビルドで十分
 - シンプルさを優先
 
中規模以上のプロジェクト・チーム開発
- カスタムビルドを推奨
 - キャッシュによる高速化の恩恵が大きい
 - テスト・Linter の統合で品質向上
 
エンタープライズプロジェクト
- カスタムビルド必須
 - 並列ジョブでテスト・ビルドを分離
 - モノレポ構成で paths フィルタ活用
 - デプロイ環境の分離(本番・ステージング)
 
カスタムビルドのメリット再確認
| 項目 | Oryx ビルド | カスタムビルド | 
|---|---|---|
| 依存関係キャッシュ | ❌ なし | ✅ あり | 
| テスト実行 | ❌ 不可 | ✅ 可能 | 
| Linter 実行 | ❌ 不可 | ✅ 可能 | 
| ビルド時間 | 遅い | 速い(2 回目以降) | 
| カスタマイズ性 | 低い | 高い | 
| セットアップ難易度 | 簡単 | やや複雑 | 
参考リンク
- Azure Static Web Apps – Build Configuration(公式ドキュメント)
 - GitHub Actions – setup-node
 - Microsoft Oryx Repository
 - Azure Static Web Apps: build app externally – johnnyreilly
 
この記事が、Azure Static Web Apps のデプロイを高速化する一助となれば幸いです。
カスタムビルドを導入することで、デプロイ時間の短縮だけでなく、テストや Linter の統合による品質向上など、開発体験が大きく向上します。
ぜひ、皆さんのプロジェクトでもお試しください!

