← Back to posts
comparison guide self-hosted · · 13 min read

SonarQube vs Semgrep vs CodeQL: Best Self-Hosted Code Quality Tools 2026

Comprehensive guide to self-hosted code quality and static analysis tools in 2026. Compare SonarQube, Semgrep, and CodeQL with Docker setup guides and feature comparisons.

OS
Editorial Team

Every software team faces the same challenge: code quality degrades over time unless you actively guard against it. Bugs sneak in, security vulnerabilities accumulate, and technical debt grows silently until it becomes a liability. The solution is static analysis — tools that scan your codebase for problems without ever executing it.

Commercial SaaS platforms have dominated this space for years, but the landscape has shifted dramatically. Today, you can run powerful, enterprise-grade code quality pipelines entirely on your own infrastructure. No external API calls, no code sent to third-party servers, no per-developer licensing fees. Just pure, self-hosted code analysis under your full control.

This guide covers the three most capable self-hosted code quality platforms available in 2026: SonarQube, Semgrep, and GitHub CodeQL. We will walk through what each tool does, how to deploy them with docker, and which one fits your team’s workflow.

Why Self-Host Your Code Quality Tools

Running code analysis on your own infrastructure is not just a privacy preference — it is a practical advantage for many organizations.

Full code privacy. Your source code never leaves your network. For teams working on proprietary software, handling regulated data, or operating under compliance frameworks like SOC 2, HIPAA, or GDPR, this is non-negotiable. Every SaaS code quality tool requires uploading at least a diff of your code to their servers. Self-hosted tools eliminate that risk entirely.

No artificial scan limits. SaaS platforms frequently throttle the number of scans, lines of code, or repositories you can analyze unless you upgrade to expensive enterprise tiers. When you self-host, the only limit is your hardware. Run scans on every commit, every branch, every pull request — as often as you want.

Custom rule sets and deep integration. Self-hosted tools let you write rules tailored to your codebase, your internal APIs, your coding standards. You can integrate analysis results directly into your internal dashboards, ticketing systems, and deployment pipelines without relying on third-party webhooks or APIs that might change.

Offline and air-gapped environments. Some teams operate in environments with restricted or no internet access — defense contractors, financial institutions, research labs. Self-hosted code quality tools work perfectly in these conditions.

Cost efficiency at scale. For teams larger than a handful of developers, SaaS per-seat pricing adds up fast. A self-hosted instance costs the same whether you have 5 developers or 500 — just the infrastructure to run it.

SonarQube: The Comprehensive Quality Gate

SonarQube is the most widely deployed self-hosted code quality platform. It supports over 30 programming languages and provides a rich web dashboard that tracks code quality metrics over time. SonarQube does not just find bugs — it enforces quality gates, tracks code coverage, measures technical debt in days, and generates executive-level reports.

Key Features

  • 30+ languages supported including Java, JavaScript, TypeScript, Python, Go, C#, C++, Ruby, PHP, Kotlin, Swift, and more
  • Quality Gates — block merges when code does not meet your standards (coverage thresholds, duplication limits, security hotspot counts)
  • Security Hotspot Review — flags potentially vulnerable code patterns for manual review
  • Clean as You Code methodology — focuses on new code quality rather than legacy debt
  • Pull Request decoration — posts analysis results directly on GitHub, GitLab, Bitbucket, and Azure DevOps PRs
  • Plugin ecosystem — extend with community and commercial plugins for additional languages and integrations

Docker Deployment

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# docker-compose.yml for SonarQube Community Edition
services:
  sonarqube:
    image: sonarqube:community
    container_name: sonarqube
    ports:
      - "9000:9000"
    environment:
      SONAR_JDBC_URL: jdbc:postgresql://sonardb:5432/sonar
      SONAR_JDBC_USERNAME: sonar
      SONAR_JDBC_PASSWORD: sonar_password
      SONAR_ES_BOOTSTRAP_CHECKS_DISABLE: "true"
    volumes:
      - sonarqube_data:/opt/sonarqube/data
      - sonarqube_extensions:/opt/sonarqube/extensions
      - sonarqube_logs:/opt/sonarqube/logs
    depends_on:
      sonardb:
        condition: service_healthy

  sonardb:
    image: postgres:16-alpine
    container_name: sonardb
    environment:
      POSTGRES_USER: sonar
      POSTGRES_PASSWORD: sonar_password
      POSTGRES_DB: sonar
    volumes:
      - postgresql_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U sonar -d sonar"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  sonarqube_data:
  sonarqube_extensions:
  sonarqube_logs:
  postgresql_data:

Start the stack:

1
docker compose up -d

After a few minutes, access the dashboard at http://localhost:9000. Default credentials are admin / admin.

Running Your First Scan

Install the SonarScanner CLI, then run:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# Install the scanner
curl -sSLo sonar-scanner.zip \
  https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-6.2.1.4610.zip
unzip sonar-scanner.zip
export PATH="$PWD/sonar-scanner-*/bin:$PATH"

# Run analysis on a project
sonar-scanner \
  -Dsonar.projectKey=my-project \
  -Dsonar.sources=src/ \
  -Dsonar.host.url=http://localhost:9000 \
  -Dsonar.token=sqp_your_generated_token

For CI/CD integration, add this to your pipeline:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# GitHub Actions example
jobs:
  sonarqube:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: SonarQube Scan
        uses: SonarSource/sonarqube-scan-action@v4
        env:
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
          SONAR_HOST_URL: https://sonarqube.your-domain.com

Semgrep: Fast, Developer-First Pattern Matching

Semgrep takes a fundamentally different approach from SonarQube. Instead of building a massive analysis engine, Semgrep uses a lightweight pattern-matching engine that understands code syntax. You write rules that look like the code you want to find, and Semgrep finds matches across your entire codebase in seconds.

Key Features

  • Syntax-aware pattern matching — understands language structure, not just regex
  • 5,000+ community rules covering OWASP Top 10, CWE Top 25, and language-specific best practices
  • YAML-based rule language — write custom rules in minutes, no compiler knowledge needed
  • Blazing fast — analyzes a large codebase in seconds, not minutes
  • Multi-language support — Python, JavaScript, TypeScript, Java, Go, Ruby, C, C++, Rust, PHP, Scala, and more
  • Semgrep Supply Chain — detects vulnerable dependencies alongside code issues
  • IDE integration — VS Code and JetBrains extensions for real-time feedback

Docker Deployment

Semgrep is distributed as a CLI tool, making it the simplest to deploy. Run it directly in CI without any server infrastructure:

1
2
3
4
5
6
# Install via pip
pip install semgrep

# Or run via Docker
docker run --rm -v "$PWD:/src" returntocorp/semgrep \
  semgrep scan --config auto /src

For team deployments with a centralized dashboard, Semgrep offers a self-hosted App (Semgrep Cloud Platform alternative). Deploy it with:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# docker-compose.yml for Semgrep App (self-hosted)
services:
  semgrep-app:
    image: returntocorp/semgrep-app:latest
    container_name: semgrep-app
    ports:
      - "8181:80"
    environment:
      SEMGREP_APP_TOKEN: your_app_token
      SEMGREP_BASE_URL: http://semgrep-app
      SEMGREP_VERSION_CHECK_URL: ""
    volumes:
      - semgrep_data:/data
    depends_on[redis](https://redis.io/)   - postgres
      - redis

  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: semgrep
      POSTGRES_USER: semgrep
      POSTGRES_PASSWORD: semgrep_secret

  redis:
    image: redis:7-alpine

volumes:
  semgrep_data:

Writing Custom Rules

Semgrep rules are written in YAML and use a syntax that mirrors the target language:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
rules:
  - id: no-hardcoded-api-keys
    pattern: |
      API_KEY = "..."
    message: "Hardcoded API key detected. Use environment variables instead."
    languages: [python]
    severity: ERROR
    metadata:
      category: security
      cwe: "CWE-798: Use of Hard-coded Credentials"

  - id: no-dangerous-eval
    pattern: eval($X)
    message: "Avoid using eval(). It can execute arbitrary code."
    languages: [javascript, typescript]
    severity: WARNING

Scan with custom rules:

1
semgrep scan --config ./rules.yaml --config auto ./src/

CI/CD Integration

1
2
3
4
5
6
7
# GitLab CI example
semgrep:
  image: returntocorp/semgrep
  script:
    - semgrep ci --config auto
  rules:
    - when: always
1
2
3
4
5
6
7
8
9
# GitHub Actions
jobs:
  semgrep:
    runs-on: ubuntu-latest
    container:
      image: returntocorp/semgrep
    steps:
      - uses: actions/checkout@v4
      - run: semgrep ci --config auto

CodeQL: Deep Semantic Analysis from GitHub

CodeQL is GitHub’s semantic code analysis engine. Unlike pattern matching, CodeQL builds a full database representation of your codebase and lets you query it using a SQL-like language. This means it can find complex bugs that span multiple functions, classes, or even files — problems that simple pattern matching cannot detect.

Key Features

  • Semantic analysis — builds a database of your code’s structure, data flow, and control flow
  • QL query language — powerful query language for writing custom security and correctness checks
  • Taint tracking — follows data from user input to dangerous sinks to find injection vulnerabilities
  • 10,000+ queries in the default security and correctness suites
  • Language support — Java, JavaScript/TypeScript, Python, Go, C#, C++, Ruby, and Swift
  • GitHub Security integration — results appear in GitHub’s security tab with full remediation guidance

Docker Deployment

CodeQL is primarily a CLI tool. You do not need to run a server — the analysis happens locally, and results are saved as SARIF files:

1
2
3
4
5
6
7
8
# Download CodeQL CLI
curl -sSLo codeql-cli.zip \
  https://github.com/github/codeql-cli-binaries/releases/download/v2.19.0/codeql-linux64.zip
unzip codeql-cli.zip

# Download the standard query packs
codeql pack download codeql/cpp-queries codeql/java-queries \
  codeql/javascript-queries codeql/python-queries codeql/go-queries

Running a CodeQL Analysis

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# 1. Create a database from your source code
codeql database create my-project-db \
  --language=python \
  --source-root=./src/

# 2. Run the default security queries
codeql database analyze my-project-db \
  --format=sarif-latest \
  --output=results.sarif \
  codeql/python-queries

# 3. Upload results to GitHub (optional)
gh api repos/OWNER/REPO/code-scanning/sarifs \
  --method POST \
  -f "sarif=@results.sarif" \
  -f "ref=refs/heads/main" \
  -f "commit_sha=$(git rev-parse HEAD)"

Writing Custom CodeQL Queries

CodeQL queries use the QL language. Here is an example that finds SQL injection vulnerabilities in Python:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
 * @name SQL injection from user input
 * @description Finds SQL queries built with unsanitized user input
 * @kind path-problem
 * @problem.severity error
 * @precision high
 * @id py/sql-injection-custom
 */
import python
import DataFlow
import Semmle.python.security.CleanPathsQuery

class SqlInjectionConfig extends TaintTracking::Configuration {
  SqlInjectionConfig() { this = "SqlInjectionConfig" }

  override predicate isSource(DataFlow::Node source) {
    exists(DataFlow::CallNode call
    |
      call.getCalleeName() = "request"
      and source.asExpr() = call.getArgument(0)
    )
  }

  override predicate isSink(DataFlow::Node sink) {
    exists(DataFlow::CallNode call
    |
      call.getCalleeName() = "execute"
      and sink.asExpr() = call.getArgument(0)
    )
  }
}

from SqlInjectionConfig cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select sink, source, sink, "SQL injection risk: user input reaches database query."

CI/CD Integration

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# GitHub Actions - CodeQL Analysis
jobs:
  analyze:
    runs-on: ubuntu-latest
    permissions:
      security-events: write
    strategy:
      fail-fast: false
      matrix:
        language: [python, javascript]
    steps:
      - uses: actions/checkout@v4
      - uses: github/codeql-action/init@v3
        with:
          languages: ${{ matrix.language }}
          queries: security-extended,security-and-quality
      - uses: github/codeql-action/autobuild@v3
      - uses: github/codeql-action/analyze@v3
        with:
          category: "/language:${{ matrix.language }}"

Feature Comparison

FeatureSonarQubeSemgrepCodeQL
Analysis TypeMulti-engine (abstract syntax tree + data flow)Syntax-aware pattern matchingSemantic database + QL queries
Languages30+20+8
Setup ComplexityMedium (needs PostgreSQL + server)Low (CLI only, no server needed)Low (CLI only)
Scan SpeedMinutes for large projectsSecondsMinutes (database creation)
Custom RulesJava plugin developmentYAML rules (minutes to write)QL queries (requires learning)
Security RulesYes (OWASP, CWE, SANS)Yes (5,000+ community rules)Yes (10,000+ default queries)
Code CoverageYes (built-in)NoNo
Code DuplicationYes (built-in)NoNo
Technical Debt TrackingYes (in days)NoNo
Pull Request DecorationGitHub, GitLab, Bitbucket, Azure DevOpsGitHub, GitLabGitHub native
Quality GatesYes (block merges on thresholds)Via CI/CD exit codesVia GitHub branch protection
IDE IntegrationSonarLint (VS Code, JetBrains, VS, Eclipse)VS Code, JetBrainsVS Code (via extension)
DashboardRich web UIWeb dashboard (self-hosted or cloud)GitHub Security tab
Supply Chain ScanningVia pluginsBuilt-in (Semgrep Supply Chain)Via Dependabot
LicenseCommunity (free), Enterprise (paid)OSS (free), Team (paid)MIT (free)
Best ForEnterprise quality managementFast developer feedbackDeep security analysis

Choosing the Right Tool

The best choice depends on what you value most.

Choose SonarQube if you need a comprehensive quality platform. It is the only tool here that tracks code coverage, duplication, and technical debt alongside bugs and vulnerabilities. The Quality Gate feature is unmatched for enforcing standards across a large team. If you want a single dashboard that gives engineering managers visibility into code health across all repositories, SonarQube is the answer. The Community Edition is free and fully self-hosted.

Choose Semgrep if you want fast, lightweight scanning with minimal setup. Semgrep scans run in seconds, rules are easy to write, and the community rule registry covers most common security issues out of the box. It integrates cleanly into any CI/CD pipeline without requiring dedicated infrastructure. For small to medium teams that want to catch bugs and security issues without adding operational overhead, Semgrep is ideal.

Choose CodeQL if your primary concern is security. Its semantic analysis and taint tracking can find complex, multi-step vulnerabilities that other tools miss. If you are building security-critical software and need to prove that your code has been analyzed for injection flaws, authentication bypasses, and data leaks, CodeQL provides the deepest analysis available. It is also the best choice if you already use GitHub — the integration is seamless.

Running Multiple Tools Together

There is no reason to pick just one. The most robust code quality pipelines layer these tools:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# Complete CI/CD pipeline with all three tools
jobs:
  semgrep-fast:
    runs-on: ubuntu-latest
    container: returntocorp/semgrep
    steps:
      - uses: actions/checkout@v4
      - run: semgrep ci --config auto
      # Fast scan completes in seconds - catches obvious issues first

  codeql-security:
    needs: semgrep-fast
    runs-on: ubuntu-latest
    strategy:
      matrix:
        language: [python, javascript]
    steps:
      - uses: actions/checkout@v4
      - uses: github/codeql-action/init@v3
        with:
          languages: ${{ matrix.language }}
      - uses: github/codeql-action/autobuild@v3
      - uses: github/codeql-action/analyze@v3
      # Deep semantic analysis catches complex vulnerabilities

  sonarqube-quality:
    needs: [semgrep-fast, codeql-security]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: SonarSource/sonarqube-scan-action@v4
        env:
          SONAR_HOST_URL: https://sonarqube.your-domain.com
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
      # Full quality gate with coverage and duplication checks

This layered approach gives you Semgrep’s speed for immediate developer feedback, CodeQL’s depth for security assurance, and SonarQube’s breadth for ongoing quality management. All three run on your own infrastructure, your code never leaves your network, and you have full control over every rule, threshold, and integration.

Final Thoughts

The era of sending your source code to third-party servers for analysis is over. In 2026, self-hosted code quality tools are mature, well-documented, and easier to deploy than ever. Whether you choose SonarQube for comprehensive quality management, Semgrep for fast pattern-based scanning, or CodeQL for deep semantic security analysis — or all three — you can build a world-class code quality pipeline that keeps your code private, your costs predictable, and your standards high.

Start with one tool, integrate it into your CI/CD pipeline, and expand from there. Your future self — and your future code reviewers — will thank you.

Frequently Asked Questions (FAQ)

Which one should I choose in 2026?

The best choice depends on your specific requirements:

  • For beginners: Start with the simplest option that covers your core use case
  • For production: Choose the solution with the most active community and documentation
  • For teams: Look for collaboration features and user management
  • For privacy: Prefer fully open-source, self-hosted options with no telemetry

Refer to the comparison table above for detailed feature breakdowns.

Can I migrate between these tools?

Most tools support data import/export. Always:

  1. Backup your current data
  2. Test the migration on a staging environment
  3. Check official migration guides in the documentation

Are there free versions available?

All tools in this guide offer free, open-source editions. Some also provide paid plans with additional features, priority support, or managed hosting.

How do I get started?

  1. Review the comparison table to identify your requirements
  2. Visit the official documentation (links provided above)
  3. Start with a Docker Compose setup for easy testing
  4. Join the community forums for troubleshooting
Advertise here