How to configure CI/CD for React with GitLab CI

Configuring CI/CD for React with GitLab CI automates testing, building, and deployment integrated with GitLab repositories. With over 12 years of React development experience since 2014 and as the creator of CoreUI, I’ve configured GitLab CI for numerous projects. GitLab CI provides powerful pipeline configuration with YAML files that run stages for test, build, and deploy automatically. This approach integrates CI/CD directly into GitLab with no external services required.

Use GitLab CI pipelines with .gitlab-ci.yml to automate React testing, building, and deployment.

Basic React pipeline:

# .gitlab-ci.yml
image: node:20

stages:
  - test
  - build
  - deploy

cache:
  paths:
    - node_modules/

variables:
  npm_config_cache: '$CI_PROJECT_DIR/.npm'
  CYPRESS_CACHE_FOLDER: '$CI_PROJECT_DIR/cache/Cypress'

before_script:
  - npm ci --cache .npm --prefer-offline

lint:
  stage: test
  script:
    - npm run lint

test:
  stage: test
  script:
    - npm test -- --coverage --watchAll=false
  coverage: '/All files[^|]*\|[^|]*\s+([\d\.]+)/'
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage/cobertura-coverage.xml

build:
  stage: build
  script:
    - npm run build
  artifacts:
    paths:
      - build/
    expire_in: 1 week
  only:
    - main
    - develop

deploy_staging:
  stage: deploy
  script:
    - echo "Deploy to staging"
    - npm run deploy:staging
  environment:
    name: staging
    url: https://staging.example.com
  only:
    - develop

deploy_production:
  stage: deploy
  script:
    - echo "Deploy to production"
    - npm run deploy:prod
  environment:
    name: production
    url: https://example.com
  when: manual
  only:
    - main

Multi-environment configuration:

# .gitlab-ci.yml
stages:
  - test
  - build
  - deploy

.test_template: &test_template
  image: node:20
  cache:
    paths:
      - node_modules/
  before_script:
    - npm ci

test:unit:
  <<: *test_template
  stage: test
  script:
    - npm run test:unit -- --coverage
  artifacts:
    reports:
      junit: junit.xml
      coverage_report:
        coverage_format: cobertura
        path: coverage/cobertura-coverage.xml

test:e2e:
  <<: *test_template
  stage: test
  script:
    - npm run test:e2e
  artifacts:
    when: on_failure
    paths:
      - cypress/screenshots/
      - cypress/videos/

.build_template: &build_template
  stage: build
  script:
    - npm ci
    - npm run build
  artifacts:
    paths:
      - build/

build:dev:
  <<: *build_template
  image: node:20
  variables:
    REACT_APP_API_URL: $DEV_API_URL
    REACT_APP_ENV: development
  only:
    - develop

build:staging:
  <<: *build_template
  image: node:20
  variables:
    REACT_APP_API_URL: $STAGING_API_URL
    REACT_APP_ENV: staging
  only:
    - staging

build:prod:
  <<: *build_template
  image: node:20
  variables:
    REACT_APP_API_URL: $PROD_API_URL
    REACT_APP_ENV: production
  only:
    - main

Deploy to GitLab Pages:

# .gitlab-ci.yml
image: node:20

pages:
  stage: deploy
  script:
    - npm ci
    - npm run build
    - mv build public
  artifacts:
    paths:
      - public
  only:
    - main

Docker build and deploy:

# .gitlab-ci.yml
stages:
  - build
  - deploy

docker_build:
  stage: build
  image: docker:latest
  services:
    - docker:dind
  before_script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME

deploy_kubernetes:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    - kubectl config set-cluster k8s --server="$KUBE_URL" --insecure-skip-tls-verify=true
    - kubectl config set-credentials admin --token="$KUBE_TOKEN"
    - kubectl config set-context default --cluster=k8s --user=admin
    - kubectl config use-context default
    - kubectl set image deployment/react-app react-app=$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME
  only:
    - main

AWS S3 deployment:

# .gitlab-ci.yml
deploy_aws:
  stage: deploy
  image: python:3.9
  before_script:
    - pip install awscli
  script:
    - npm ci
    - npm run build
    - aws s3 sync build/ s3://$S3_BUCKET --delete
    - aws cloudfront create-invalidation --distribution-id $CLOUDFRONT_ID --paths "/*"
  environment:
    name: production
    url: https://example.com
  only:
    - main

Parallel jobs:

# .gitlab-ci.yml
test:
  stage: test
  parallel:
    matrix:
      - NODE_VERSION: ['18', '20', '22']
  image: node:${NODE_VERSION}
  script:
    - npm ci
    - npm test

Include templates:

# .gitlab-ci.yml
include:
  - template: Security/SAST.gitlab-ci.yml
  - template: Security/Dependency-Scanning.gitlab-ci.yml

stages:
  - test
  - build
  - deploy

Best Practice Note

Use cache for node_modules to speed up pipeline runs. Store secrets in GitLab CI/CD variables (Settings → CI/CD → Variables). Use only or rules to control when jobs run. Manual deployment to production with when: manual prevents accidental deploys. Artifacts persist build output for deployment stages. Use templates to avoid repetition. This is how we configure GitLab CI for CoreUI React projects—automated testing, environment-specific builds, and controlled deployments with GitLab’s integrated CI/CD platform.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author