Summary
Optimize GitHub Actions workflows to reduce billable runner minutes while maintaining all existing functionality and leaving room for future enhancements.
Background
Current workflow analysis reveals several cost optimization opportunities:
- Multiple workflows run on every PR regardless of what files changed
- Playwright tests use 4 parallel shards (4× runner cost)
test-docker-compose duplicates testing already covered by Playwright
- No Docker layer caching between workflow runs
Proposed Changes
1. Remove test-docker-compose from PRs (keep on master only)
Estimated savings: ~3-5 min per PR
Change the trigger from:
on:
push:
branches: [master]
pull_request:
types: [opened, synchronize]
to:
on:
push:
branches: [master]
Rationale: Playwright tests already validate the full Docker stack works. Running both is redundant for PRs.
2. Reduce Playwright shards from 4 to 2
Estimated savings: ~50% of Playwright costs
Update the matrix in playwright.yml:
strategy:
fail-fast: false
matrix:
shardIndex: [1, 2] # was [1, 2, 3, 4]
shardTotal: [2] # was [4]
Update artifact download pattern accordingly.
Tradeoff: Tests will take ~2x longer to complete, but cost half as much.
3. Add path filtering to lint-backend.yml
Estimated savings: Skip ~2-3 min on frontend-only PRs
Add a changes job similar to what playwright.yml already uses:
jobs:
changes:
runs-on: ubuntu-latest
outputs:
backend: ${{ steps.filter.outputs.backend }}
steps:
- uses: actions/checkout@v5
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
backend:
- backend/**
- pyproject.toml
- .github/workflows/lint-backend.yml
lint-backend:
needs: [changes]
if: ${{ needs.changes.outputs.backend == 'true' }}
# ... existing job config
Add an alls-green job for branch protection compatibility.
4. Add path filtering to test-backend.yml
Estimated savings: Skip ~5-8 min on frontend-only PRs
Same pattern as above:
filters: |
backend:
- backend/**
- docker-compose*.yml
- .github/workflows/test-backend.yml
5. Add path filtering to generate-client.yml
Estimated savings: Skip ~3-4 min when only frontend/docs change
Only run when backend API-related files change:
filters: |
api:
- backend/app/api/**
- backend/app/models.py
- backend/app/main.py
- scripts/generate-client.sh
- .github/workflows/generate-client.yml
6. (Optional/Future) Add Docker layer caching
Potential additional savings: 1-3 min per Docker build
Consider adding Docker layer caching using docker/build-push-action with GitHub Actions cache:
- uses: docker/build-push-action@v5
with:
context: .
cache-from: type=gha
cache-to: type=gha,mode=max
This is more complex to implement but would speed up Docker builds across all workflows.
Checklist
Estimated Impact
| Scenario |
Current Minutes (est.) |
After Optimization (est.) |
| Backend-only PR |
~35-45 min |
~20-25 min |
| Frontend-only PR |
~35-45 min |
~10-15 min |
| Full-stack PR |
~35-45 min |
~25-30 min |
| Push to master |
~40-50 min |
~40-50 min (unchanged) |
Note: Actual savings depend on your PR patterns. If most PRs touch both frontend and backend, savings will be closer to 30-40%. If many PRs are frontend-only or backend-only, savings could reach 60-70%.
Summary
Optimize GitHub Actions workflows to reduce billable runner minutes while maintaining all existing functionality and leaving room for future enhancements.
Background
Current workflow analysis reveals several cost optimization opportunities:
test-docker-composeduplicates testing already covered by PlaywrightProposed Changes
1. Remove
test-docker-composefrom PRs (keep on master only)Estimated savings: ~3-5 min per PR
Change the trigger from:
to:
Rationale: Playwright tests already validate the full Docker stack works. Running both is redundant for PRs.
2. Reduce Playwright shards from 4 to 2
Estimated savings: ~50% of Playwright costs
Update the matrix in
playwright.yml:Update artifact download pattern accordingly.
Tradeoff: Tests will take ~2x longer to complete, but cost half as much.
3. Add path filtering to
lint-backend.ymlEstimated savings: Skip ~2-3 min on frontend-only PRs
Add a
changesjob similar to whatplaywright.ymlalready uses:Add an
alls-greenjob for branch protection compatibility.4. Add path filtering to
test-backend.ymlEstimated savings: Skip ~5-8 min on frontend-only PRs
Same pattern as above:
5. Add path filtering to
generate-client.ymlEstimated savings: Skip ~3-4 min when only frontend/docs change
Only run when backend API-related files change:
6. (Optional/Future) Add Docker layer caching
Potential additional savings: 1-3 min per Docker build
Consider adding Docker layer caching using
docker/build-push-actionwith GitHub Actions cache:This is more complex to implement but would speed up Docker builds across all workflows.
Checklist
test-docker-compose.yml- remove PR triggerplaywright.yml- reduce to 2 shardslint-backend.yml- add path filtering + alls-green jobtest-backend.yml- add path filtering + alls-green jobgenerate-client.yml- add path filtering + alls-green jobEstimated Impact
Note: Actual savings depend on your PR patterns. If most PRs touch both frontend and backend, savings will be closer to 30-40%. If many PRs are frontend-only or backend-only, savings could reach 60-70%.