How to configure CI/CD for React with GitHub Actions
Configuring CI/CD for React with GitHub Actions automates testing, building, and deployment whenever code changes are pushed. As the creator of CoreUI with over 12 years of React experience since 2014, I’ve configured GitHub Actions for numerous production React applications. GitHub Actions provides built-in CI/CD with YAML workflows that run tests, create optimized builds, and deploy to various hosting platforms. This approach ensures code quality, catches bugs early, and enables automated deployments with every commit.
Use GitHub Actions workflows to automate React testing, building, and deployment with event-triggered pipelines.
Basic React CI workflow:
# .github/workflows/ci.yml
name: React CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x, 20.x]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run linter
run: npm run lint
- name: Run tests
run: npm test -- --coverage --watchAll=false
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage/coverage-final.json
build:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20.x
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build application
run: npm run build
env:
CI: true
- name: Upload build artifacts
uses: actions/upload-artifact@v3
with:
name: build
path: build/
retention-days: 7
Deploy to GitHub Pages:
# .github/workflows/deploy-pages.yml
name: Deploy to GitHub Pages
on:
push:
branches: [main]
permissions:
contents: read
pages: write
id-token: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20.x
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
env:
PUBLIC_URL: /repo-name
- name: Setup Pages
uses: actions/configure-pages@v3
- name: Upload artifact
uses: actions/upload-pages-artifact@v2
with:
path: ./build
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v2
Deploy to Netlify:
# .github/workflows/deploy-netlify.yml
name: Deploy to Netlify
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20.x
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
env:
REACT_APP_API_URL: ${{ secrets.API_URL }}
- name: Deploy to Netlify
uses: nwtgck/actions-netlify@v2
with:
publish-dir: './build'
production-branch: main
github-token: ${{ secrets.GITHUB_TOKEN }}
deploy-message: 'Deploy from GitHub Actions'
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
Deploy to Vercel:
# .github/workflows/deploy-vercel.yml
name: Deploy to Vercel
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20.x
- name: Install Vercel CLI
run: npm install --global vercel@latest
- name: Pull Vercel Environment Information
run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}
- name: Build Project Artifacts
run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }}
- name: Deploy to Vercel
run: vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }}
Deploy to AWS S3 and CloudFront:
# .github/workflows/deploy-aws.yml
name: Deploy to AWS
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20.x
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1
- name: Deploy to S3
run: aws s3 sync build/ s3://${{ secrets.S3_BUCKET }} --delete
- name: Invalidate CloudFront
run: |
aws cloudfront create-invalidation \
--distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }} \
--paths "/*"
Environment-specific deployments:
# .github/workflows/deploy-environments.yml
name: Deploy to Environments
on:
push:
branches:
- main
- staging
- develop
jobs:
deploy-dev:
if: github.ref == 'refs/heads/develop'
runs-on: ubuntu-latest
environment: development
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20.x
- run: npm ci
- run: npm run build
env:
REACT_APP_API_URL: ${{ secrets.DEV_API_URL }}
REACT_APP_ENV: development
- name: Deploy to Dev
run: echo "Deploy to development server"
deploy-staging:
if: github.ref == 'refs/heads/staging'
runs-on: ubuntu-latest
environment: staging
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20.x
- run: npm ci
- run: npm run build
env:
REACT_APP_API_URL: ${{ secrets.STAGING_API_URL }}
REACT_APP_ENV: staging
- name: Deploy to Staging
run: echo "Deploy to staging server"
deploy-prod:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20.x
- run: npm ci
- run: npm run build
env:
REACT_APP_API_URL: ${{ secrets.PROD_API_URL }}
REACT_APP_ENV: production
- name: Deploy to Production
run: echo "Deploy to production server"
Lighthouse performance check:
# .github/workflows/lighthouse.yml
name: Lighthouse CI
on:
pull_request:
branches: [main]
jobs:
lighthouse:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20.x
- run: npm ci
- run: npm run build
- name: Run Lighthouse CI
uses: treosh/lighthouse-ci-action@v10
with:
urls: |
http://localhost:3000
uploadArtifacts: true
temporaryPublicStorage: true
Bundle size check:
# .github/workflows/bundle-size.yml
name: Bundle Size Check
on:
pull_request:
branches: [main]
jobs:
bundle-size:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20.x
- run: npm ci
- run: npm run build
- name: Analyze bundle size
uses: andresz1/size-limit-action@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
Docker build and push:
# .github/workflows/docker.yml
name: Docker Build and Push
on:
push:
branches: [main]
tags: ['v*']
jobs:
docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: username/react-app
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
cache-from: type=gha
cache-to: type=gha,mode=max
Package.json scripts:
{
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"test:ci": "react-scripts test --coverage --watchAll=false --ci",
"lint": "eslint src/**/*.{js,jsx}",
"lint:fix": "eslint src/**/*.{js,jsx} --fix",
"format": "prettier --write \"src/**/*.{js,jsx,json,css}\"",
"analyze": "source-map-explorer 'build/static/js/*.js'"
}
}
Best Practice Note
Use matrix strategy to test against multiple Node.js versions ensuring compatibility. Cache npm dependencies with cache: 'npm' for faster builds. Run tests with --watchAll=false in CI to prevent hanging. Store environment secrets in GitHub repository settings under Settings → Secrets. Use environment protection rules for production deployments requiring manual approval. Upload build artifacts for debugging and deployment. Run Lighthouse CI on pull requests to catch performance regressions. This is how we configure CI/CD for CoreUI React applications—automated testing, optimized builds, and reliable deployments ensuring production-ready releases with every commit.



