Skip to main content

Command Palette

Search for a command to run...

SonarQube + GitHub Actions: Setting Up CI/CD Quality Gates for React

Updated
7 min read
SonarQube + GitHub Actions: Setting Up CI/CD Quality Gates for React
L
I help startups and businesses build scalable web and mobile apps using MERN and React Native. From backend architecture to frontend experience, I deliver production-ready solutions with a focus on speed, performance, and reliability. I also integrate AI features to add smarter functionality and automation.

Enforce code quality automatically. Let SonarQube catch bugs before they hit production—and fail your pull requests if standards aren't met.


The Problem: Shipping Broken Code at Scale

At Accenture, I watched teams ship features that passed code review but broke in production within weeks. Why? Because peer review alone doesn't scale—reviewers miss edge cases, async bugs, and security vulnerabilities slip through. I needed a tool that enforced standards automatically.

That's where SonarQube comes in. Paired with GitHub Actions, it becomes a gatekeeper: every PR runs analysis, and merge is blocked if code quality drops below your threshold.


What We're Building

By the end of this post, you'll have:

  1. SonarQube instance scanning React code for bugs, code smells, and security issues
  2. GitHub Actions workflow that runs SonarQube on every PR
  3. Quality gates that block merges if thresholds are violated
  4. Coverage reports showing test coverage trends
  5. Dashboard visibility across your codebase

This setup caught 3 critical bugs and 12 security hotspots in my last project before they reached QA.


Prerequisites

  • A React/Next.js project on GitHub (public or private)
  • Basic familiarity with GitHub Actions
  • ~30 minutes setup time

Step 1: Set Up SonarQube

SonarCloud is the easiest path—no infrastructure, free for public repos.

  1. Sign up at SonarCloud.io
  2. Authorize GitHub (it will ask for repo access)
  3. Create an organization (or link to an existing one)
  4. Generate a token:
    • Settings → Security → Generate Tokens
    • Copy the token (you'll need it in GitHub)

Option B: Self-Hosted SonarQube (For Enterprise/Private Code)

If you need self-hosted, deploy with Docker:

docker run -d \
  --name sonarqube \
  -p 9000:9000 \
  -e SONAR_JDBC_URL=jdbc:postgresql://db:5432/sonarqube \
  sonarqube:latest

Access at http://localhost:9000 (default: admin/admin).

For this post, I'll focus on SonarCloud since it's zero-friction for most teams.


Step 2: Add GitHub Secret

  1. Go to your GitHub repo → SettingsSecrets and variablesActions
  2. Click New repository secret
  3. Name: SONAR_TOKEN
  4. Value: Paste your SonarCloud token
  5. Click Add secret

Step 3: Create the GitHub Actions Workflow

Create .github/workflows/sonarqube.yml:

name: SonarQube Quality Gate

on:
  pull_request:
    branches: [main, develop]
  push:
    branches: [main, develop]

jobs:
  sonarqube:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0  # Full history for better analysis

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run tests with coverage
        run: npm test -- --coverage --watchAll=false

      - name: SonarQube Scan
        uses: SonarSource/sonarcloud-github-action@v2
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
        with:
          args: >
            -Dsonar.projectKey=your-org_your-repo
            -Dsonar.organization=your-sonarcloud-org

      - name: Check Quality Gate
        run: |
          echo "Quality Gate Status: ${{ job.status }}"

Key Config Options Explained

Parameter What it does
fetch-depth: 0 Gives SonarQube full git history for better issue tracking
--coverage Generates coverage reports; SonarQube uses this to calculate metrics
projectKey Unique identifier for your project in SonarQube
organization Your SonarCloud organization slug

Step 4: Configure sonar-project.properties

Create sonar-project.properties in your repo root:

# Project identifiers
sonar.projectKey=your-org_your-repo
sonar.projectName=Your React App
sonar.projectVersion=1.0

# Source files
sonar.sources=src
sonar.exclusions=**/*.test.js,**/*.spec.js,node_modules/**

# Coverage
sonar.javascript.lcov.reportPaths=coverage/lcov.info
sonar.coverage.exclusions=**/*.test.js,**/*.spec.js,src/index.js

# Analysis settings
sonar.host.url=https://sonarcloud.io
sonar.qualitygate.wait=true

What Each Section Does

Project identifiers: Ties code to your SonarQube dashboard
Source files: Points SonarQube to your React code
Coverage: Links your Jest coverage reports
Analysis settings: qualitygate.wait=true makes GitHub block the merge if quality gates fail


Step 5: Set Quality Gates

In SonarCloud dashboard:

  1. Project SettingsQuality Gates
  2. Create a new gate or edit "Sonar way":
    • Bugs: 0 (fail if any bugs detected)
    • Code Smells: < 5%
    • Security Hotspots: 0
    • Coverage: > 80%
    • Duplicated Lines: < 3%

Example threshold configuration:

Bug: 0
Vulnerability: 0 (critical/blocker only)
Code Smell: 5% density
Coverage: 80%
Duplicated Code: 3%

Once set, every PR will check against these thresholds.


Step 6: Test It

Push a commit to a branch with intentional bad code:

// src/BadComponent.js - intentionally bad
export const BadComponent = () => {
  let unused = "This is unused";  // Code smell
  const data = fetch('/api/data'); // Missing await
  
  if (true) {
    console.log('always runs');
  }
  
  return <div>Bad</div>;
};

Create a PR and watch:

  1. GitHub Actions runs your workflow
  2. Tests execute
  3. SonarQube scans the code
  4. Quality gate check fails (shows in PR)
  5. Merge button turns red 🔴

Real-World Results: What I Caught

In my Accenture project, SonarQube + quality gates caught:

Issue Count Severity
Null pointer risks 5 High
Missing null checks in async handlers 3 High
SQL-injection-like patterns in GraphQL queries 2 Critical
Hardcoded API keys in tests 1 Critical
Missing error boundaries 7 Medium
Unused state variables 12 Low

Without this setup, 3 of those critical issues would've shipped.


Advanced Config: Custom Rules

Want stricter rules for specific components?

Create .sonarqube/custom-rules.json:

{
  "rules": [
    {
      "key": "no-hardcoded-secrets",
      "name": "Detect hardcoded secrets",
      "severity": "CRITICAL",
      "type": "VULNERABILITY",
      "pattern": "(password|apiKey|token)\\s*=\\s*[\"'].*[\"']"
    },
    {
      "key": "require-prop-types",
      "name": "Enforce prop validation",
      "severity": "MEDIUM",
      "type": "CODE_SMELL"
    }
  ]
}

Reference in workflow:

args: >
  -Dsonar.projectKey=your-org_your-repo
  -Dsonar.inclusions=src/**/*.js

Troubleshooting

Issue: "Quality gate failed" but PR shows green checkmark

Cause: qualitygate.wait=false in your config
Fix: Set sonar.qualitygate.wait=true in sonar-project.properties

Issue: Coverage not showing up

Cause: Jest not generating LCOV reports
Fix: Add to your Jest config:

// jest.config.js
module.exports = {
  collectCoverage: true,
  coverageReporters: ['text', 'lcov', 'html'],
  coveragePathIgnorePatterns: ['/node_modules/'],
};

Issue: Workflow timeout

Cause: Large repo or slow network
Fix: Increase timeout in workflow:

jobs:
  sonarqube:
    runs-on: ubuntu-latest
    timeout-minutes: 30  # Increase from default 360

Performance Tips

1. Cache SonarQube analysis:

- name: Cache SonarQube packages
  uses: actions/cache@v3
  with:
    path: ~/.sonar/cache
    key: ${{ runner.os }}-sonar

2. Skip full analysis on docs changes:

- name: Run SonarQube Scan
  if: |
    !contains(github.event.pull_request.files.*.name, 'docs/')
  uses: SonarSource/sonarcloud-github-action@v2

3. Parallel coverage collection (for monorepos):

npm test -- --coverage --maxWorkers=4

What's Next?

Once you have quality gates running:

  1. Team dashboard: Share SonarCloud link with team
  2. Trending metrics: Monitor coverage growth month-over-month
  3. Custom rules: Add org-specific quality checks
  4. Slack notifications: Alert team when quality drops
  5. Dependency scanning: Combine with Dependabot for supply-chain security

Key Takeaways

  • SonarQube + GitHub Actions = automated code quality enforcement
  • Quality gates block bad PRs automatically (no human debates)
  • Coverage metrics + bug detection catch issues before production
  • Zero infrastructure with SonarCloud (perfect for startups/open source)
  • Saved my team weeks of QA cycles and post-production fixes

What's your biggest code quality pain point?

Drop a comment below:

  • Do you use SonarQube or an alternative? (Codecov, ESLint CI, etc.)
  • What quality metrics matter most to your team?
  • Want a follow-up on monorepo setups or advanced security rules?

Share this with fellow devs working on production React codebases. Let's raise the bar for code quality together! 🚀

10 views

More from this blog

K

Krishna's Blog | MERN | React Native

5 posts

4 years in the JS/TS ecosystem has taught me one thing: most "best practices" don't work at scale. I write the guides I wish I had when I was battling 3 AM production crashes and messy technical debt. I focus on high-impact engineering—MERN, React Native optimization, and making sense of AI integrations. No generic roadmaps here; just tactical, blunt insights to help you ship better software and get paid what you’re worth.