// "GitHub Actions optimization patterns and deployment workflows for static sites. Use when creating CI/CD pipelines, optimizing builds, or troubleshooting GitHub Actions."
| name | github-workflow |
| description | GitHub Actions optimization patterns and deployment workflows for static sites. Use when creating CI/CD pipelines, optimizing builds, or troubleshooting GitHub Actions. |
For static site deployment to GitHub Pages:
name: Deploy
on:
push:
branches: [main]
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: "pages"
cancel-in-progress: false
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run build
- uses: actions/upload-pages-artifact@v3
with:
path: ./dist
deploy:
needs: build
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- uses: actions/deploy-pages@v4
id: deployment
Critical settings:
permissions: Required for GitHub Pages deploymentconcurrency: Prevents simultaneous deploymentscache: 'npm': Caches dependencies automatically- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm' # Automatic npm cache
How it works: Caches node_modules based on package-lock.json hash.
When cache is invalidated: When package-lock.json changes.
For expensive build steps:
- uses: actions/cache@v3
with:
path: |
.next/cache
.astro/cache
key: ${{ runner.os }}-build-${{ hashFiles('**/*.ts', '**/*.tsx') }}
restore-keys: |
${{ runner.os }}-build-
Use when: Build takes >1 minute and can use previous artifacts.
cache: 'npm')on:
push:
paths:
- 'src/**'
- 'content/**'
- 'package.json'
Use when: Large repo, only want to run on relevant changes.
Include [skip ci] in commit message to skip workflow.
Repository Settings → Secrets → Add:
ACTIONS_RUNNER_DEBUG: trueACTIONS_STEP_DEBUG: true- name: Debug
run: |
echo "Event: ${{ github.event_name }}"
echo "Ref: ${{ github.ref }}"
echo "SHA: ${{ github.sha }}"
Cache not restoring:
Deployment fails:
Build works locally, fails in CI:
package.jsonAim for:
Measure: Actions tab shows timing breakdown per step.
For testing across versions:
strategy:
matrix:
node: [18, 20]
os: [ubuntu-latest, windows-latest]
fail-fast: true # Stop all on first failure
runs-on: ${{ matrix.os }}
steps:
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
Use when: Need to verify compatibility across versions/platforms. Avoid when: Only deploying to single environment (use single config).
env:
API_KEY: ${{ secrets.API_KEY }}
Add secrets: Repository Settings → Secrets and variables → Actions
Never log secrets: GitHub automatically masks secrets in logs, but avoid echo $SECRET.
# On push to main
on:
push:
branches: [main]
# On PR to main
on:
pull_request:
branches: [main]
# Manual trigger
on:
workflow_dispatch:
# Scheduled (cron)
on:
schedule:
- cron: '0 0 * * 0' # Weekly on Sunday
jobs:
build:
runs-on: ubuntu-latest
steps: [...]
deploy:
needs: build # Wait for build
runs-on: ubuntu-latest
steps: [...]
jobs:
lint:
runs-on: ubuntu-latest
steps: [...]
test:
runs-on: ubuntu-latest
steps: [...]
# Both run simultaneously
- uses: actions/upload-artifact@v3
with:
name: build
path: dist/
retention-days: 7
- uses: actions/download-artifact@v3
with:
name: build
path: dist/
Use when: Passing data between jobs.
@v4 or commit SHAsAlready fast? These optimizations have diminishing returns:
Focus on:
For GitHub Pages deployment:
For custom domain: