
GitHub Actions CI/CD for Frontend Apps: The Complete Setup
A well-configured GitHub Actions pipeline catches bugs before production, automates deployments, and maintains code quality without manual work. Build the complete frontend CI/CD pipeline.
What a Great Frontend CI/CD Pipeline Does
A complete pipeline should: run type checks and linting on every PR, run unit and integration tests, build the application to verify no build errors, run E2E tests on preview deployments, and deploy automatically to staging/production on merge.
The Complete Workflow
# .github/workflows/ci.yml
name: CI/CD
on:
push:
branches: [main, staging]
pull_request:
branches: [main]
env:
NODE_VERSION: '22'
PNPM_VERSION: '9'
jobs:
quality:
name: Quality Checks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'
- run: pnpm install --frozen-lockfile
- name: Type check
run: pnpm typecheck
- name: Lint
run: pnpm lint
- name: Unit tests
run: pnpm test:run --coverage
- name: Upload coverage
uses: actions/upload-artifact@v4
with:
name: coverage
path: coverage/
build:
name: Build Check
runs-on: ubuntu-latest
needs: quality
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with: { version: '${{ env.PNPM_VERSION }}' }
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'
- run: pnpm install --frozen-lockfile
- name: Build
run: pnpm build
env:
DATABASE_URL: ${{ secrets.DATABASE_URL_CI }}
e2e:
name: E2E Tests
runs-on: ubuntu-latest
needs: build
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with: { version: '${{ env.PNPM_VERSION }}' }
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'
- run: pnpm install --frozen-lockfile
- name: Install Playwright browsers
run: npx playwright install --with-deps chromium
- name: Run E2E tests
run: pnpm test:e2e
env:
BASE_URL: ${{ steps.deploy-preview.outputs.url }}
deploy-production:
name: Deploy to Production
runs-on: ubuntu-latest
needs: [quality, build]
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
steps:
- uses: actions/checkout@v4
- name: Deploy to Vercel
run: npx vercel --prod --token=${{ secrets.VERCEL_TOKEN }}
Caching for Speed
# Add to any job that installs dependencies
- uses: actions/cache@v4
with:
path: |
~/.pnpm-store
${{ github.workspace }}/.next/cache
key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
Branch Protection Rules
In GitHub repo settings, require these status checks before merging:
- quality (type check + lint + tests)
- build (successful build)
- Require up-to-date branches before merging
Notifications on Failure
- name: Notify Slack on failure
if: failure()
uses: slackapi/[email protected]
with:
payload: |
{
"text": "CI failed on ${{ github.ref }}\nAuthor: ${{ github.actor }}\nRun: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
A CI/CD pipeline is infrastructure, not overhead. The time you invest in this setup comes back tenfold in bugs caught before production and deploys you never have to think about.
Get weekly highlights
No spam, unsubscribe anytime.
Cal.com
Open source scheduling — self-host your booking system, replace Calendly. Free & privacy-first.
Fillout
Powerful form builder for devs — integrates with Next.js, React, Notion, Airtable. Save hours of coding.



Comments (0)
Sign in to comment
No comments yet. Be the first to comment!