CI/CD for React with GitHub Actions
Lint, test, and build your React app on every push, then publish the static bundle.
A React single-page app compiles to static HTML, CSS, and JavaScript, which makes its pipeline simple: check quality, build a bundle, and upload it. This recipe covers both Create React App and Vite projects with one workflow you can adapt by changing the build command.
What the pipeline does
- install deps with npm ci
- lint with eslint
- run tests in CI mode
- build the static bundle
- upload or deploy the output
The workflow
This builds a React app and deploys the output to GitHub Pages. For CRA the build output is build/; for Vite it is dist/ (adjust the path).
name: CI
on:
push:
branches: [main]
pull_request:
permissions:
contents: read
pages: write
id-token: write
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 lint --if-present
- run: npm test -- --watchAll=false
env:
CI: true
- run: npm run build
- uses: actions/upload-pages-artifact@v3
with:
path: build
deploy:
needs: build
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment:
name: github-pages
steps:
- id: deployment
uses: actions/deploy-pages@v4Caching and speed
cache: npm restores the npm download cache so installs are quick. Jest and Vitest both honor CI=true to run once and exit. The build is the slowest step for large component trees; running it on faster, cheaper managed runners like Latchkey trims wall-clock time on every PR.
Deploying
GitHub Pages (shown above) is free and ideal for project sites. For production traffic, upload the bundle to S3 behind CloudFront, or connect the repo to Netlify, Vercel, or Cloudflare Pages for automatic deploys and preview URLs on pull requests.
Key takeaways
- A React SPA pipeline is just check, build, upload.
- Set CI=true so test runners exit instead of watching.
- GitHub Pages is the simplest host; S3+CloudFront scales for production.