zudo-cloudflare-wisdom

Type to search...

to open search from anywhere

Multi-Output Deploy

CreatedApr 4, 2026Takeshi Takatsudo

Combining multiple build outputs into a single Pages deploy

The Pattern

Some projects produce multiple build outputs (e.g., a blog + a doc site) that need to be combined into a single Cloudflare Pages deployment.

Example: Blog + Doc Site

From our zpaper project, which deploys an Astro blog and a zudo-doc documentation site under one Pages project:

graph TB A[Build blog] --> D[Combine outputs] B[Build doc] --> D C[Functions] --> D D --> E[Deploy to CF Pages]

Build Job

Build both outputs and cache them:

  build:
    steps:
      - run: pnpm build      # Blog -> blog/dist/
      - run: pnpm doc:build   # Docs -> doc/dist/

      - uses: actions/cache/save@v4
        with:
          path: blog/dist/
          key: blog-build-${{ github.run_id }}

      - uses: actions/cache/save@v4
        with:
          path: doc/dist/
          key: doc-build-${{ github.run_id }}

      - uses: actions/cache/save@v4
        with:
          path: functions/
          key: functions-build-${{ github.run_id }}

Combine and Deploy

  deploy:
    needs: [build, test]
    steps:
      - uses: actions/cache/restore@v4
        with:
          path: blog/dist/
          key: blog-build-${{ github.run_id }}

      - uses: actions/cache/restore@v4
        with:
          path: doc/dist/
          key: doc-build-${{ github.run_id }}

      - uses: actions/cache/restore@v4
        with:
          path: functions/
          key: functions-build-${{ github.run_id }}

      - name: Combine outputs
        run: |
          mkdir -p deploy/pj/my-site
          cp -r blog/dist/* deploy/pj/my-site/
          mkdir -p deploy/pj/my-site/doc
          cp -r doc/dist/* deploy/pj/my-site/doc/

      - name: Deploy
        run: |
          pnpm dlx wrangler@4 pages deploy deploy \
            --project-name=my-site \
            --branch=main \
            --commit-hash=${GITHUB_SHA}
        env:
          CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}

Cache vs Artifacts

Using actions/cache instead of actions/upload-artifact for inter-job data:

CacheArtifact
StorageShared across runs, auto-evictedPer-run, retention-days based
AccumulationNo accumulation issuesCan bloat storage if retention is high
SpeedFast for repeated contentFast

💡 Tip

Use actions/cache with a github.run_id scoped key for inter-job data. This avoids artifact storage accumulation across many CI runs.

Functions with Dependencies

If your Pages Functions import npm packages, install them before deploying:

      - name: Install function dependencies
        run: |
          rm -rf node_modules
          pnpm add -w minisearch

      - name: Deploy
        run: pnpm dlx wrangler@4 pages deploy deploy --project-name=my-site