zudo-cloudflare-wisdom

Type to search...

to open search from anywhere

Production Deploy

CreatedApr 4, 2026Takeshi Takatsudo

GitHub Actions workflow for main branch deploys

Standard Workflow

The production deploy workflow triggers on push to main:

name: Production Deploy

on:
  push:
    branches:
      - main

concurrency:
  group: production-deploy
  cancel-in-progress: false

permissions:
  contents: read

⚠️ Do NOT Cancel In-Progress Deploys

Set cancel-in-progress: false for production deploys. If two pushes happen quickly, you want both to complete in order, not cancel the first one mid-deploy.

Build Job

jobs:
  build-site:
    name: Build Site
    runs-on: ubuntu-latest
    timeout-minutes: 15

    steps:
      - name: Checkout repository
        uses: actions/checkout@v5
        with:
          fetch-depth: 0

      - name: Setup pnpm
        uses: pnpm/action-setup@v4

      - name: Setup Node.js
        uses: actions/setup-node@v5
        with:
          node-version: 22

      - name: Install dependencies
        run: pnpm install --frozen-lockfile

      - name: Build site
        run: pnpm build

      - name: Upload build artifact
        uses: actions/upload-artifact@v7
        with:
          name: dist-out
          path: dist/
          retention-days: 1

💡 fetch-depth: 0

Use fetch-depth: 0 if your build needs git history (e.g., for doc metainfo showing creation/update dates).

Deploy Job

  deploy:
    name: Deploy to Cloudflare Pages
    needs: [build-site]
    runs-on: ubuntu-latest
    timeout-minutes: 10

    steps:
      - name: Download site artifact
        uses: actions/download-artifact@v7
        with:
          name: dist-out
          path: dist-out/

      - name: Prepare deploy directory
        run: |
          mkdir -p deploy/pj/my-site
          if [ -d dist-out/client ]; then
            cp -r dist-out/client/. deploy/pj/my-site/
          else
            cp -r dist-out/. deploy/pj/my-site/
          fi
          echo '/ /pj/my-site/ 302' > deploy/_redirects

      - name: Deploy to Cloudflare Pages (production)
        run: |
          npx wrangler@4 pages deploy deploy \
            --project-name=my-site \
            --branch=main \
            --commit-hash="${GITHUB_SHA}" \
            --commit-message="Production deploy: ${GITHUB_SHA}"
        env:
          CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}

Separating Build and Deploy

Splitting build and deploy into separate jobs is recommended because:

  1. Artifact inspection: You can download and inspect the build output if needed
  2. Retry deploys: If the deploy fails (network issue), you can re-run just the deploy job
  3. Test between build and deploy: Insert test jobs (e2e, lighthouse) between build and deploy