SonarQube

Continuous code quality and security inspection

Developer Tools & Git ★ 11k stars Medium setup LGPL-3.0

SonarQube is a platform for continuous inspection of code quality and security, detecting bugs, vulnerabilities, and code smells. It targets development teams enforcing code standards. It is deployed via Docker with a database.

Key features

  • Detects bugs and vulnerabilities
  • Supports many languages
  • Quality gates for CI
  • Pull request decoration

Pros & cons

Strengths

  • Strong static analysis
  • Broad language coverage
  • CI-friendly quality gates

Trade-offs

  • Heavy memory requirements
  • Best features in paid editions

SonarQube replaces

Last reviewed Aug 26, 2026 · 879 words

The first time SonarQube refuses to start, the cause is a kernel setting, not SonarQube. Run sysctl -w vm.max_map_count=524288 on the Docker host, make it permanent in /etc/sysctl.conf, and the embedded Elasticsearch stops dying on boot. Get past that and you have the best free static analysis you can run on your own hardware, provided you can give it 2 GB of RAM and a Postgres, and provided you accept that branch analysis and pull request decoration live in the paid editions.

The compose that boots on the second try

services:
  sonarqube:
    image: sonarqube:community
    depends_on: [db]
    ports:
      - "9000:9000"
    environment:
      SONAR_JDBC_URL: jdbc:postgresql://db:5432/sonar
      SONAR_JDBC_USERNAME: sonar
      SONAR_JDBC_PASSWORD: change-me
    volumes:
      - sonarqube_data:/opt/sonarqube/data
      - sonarqube_extensions:/opt/sonarqube/extensions
      - sonarqube_logs:/opt/sonarqube/logs
    restart: unless-stopped
  db:
    image: postgres:16
    environment:
      POSTGRES_USER: sonar
      POSTGRES_PASSWORD: change-me
      POSTGRES_DB: sonar
    volumes:
      - pg_data:/var/lib/postgresql/data
volumes:
  sonarqube_data:
  sonarqube_extensions:
  sonarqube_logs:
  pg_data:

Give it 1 to 2 minutes; the log line to wait for is "SonarQube is operational". First login is admin / admin and it forces a password change immediately. The image will run without Postgres on an embedded H2 database, and that mode exists only for evaluation: it cannot be upgraded, so do not start a project history on it you intend to keep.

2 GB is the floor and 4 GB is where it stops swapping

SonarQube is 3 JVMs in 1 container: the web server, the compute engine that processes analysis reports, and Elasticsearch for search and issue indexing. The catalogue's 2,048 MB minimum is real for a few small projects. The moment you analyse a 200,000-line codebase or 2 reports land at once, the compute engine wants heap of its own, and 4 GB is the number at which I stopped seeing the container restart under memory pressure. This is not a Raspberry Pi service. It is also not a service you need running 24 hours a day if analysis only happens on push; a scheduled stop overnight is a legitimate way to reclaim the RAM.

Scanning is 1 command per project, and the quality gate is the point

Create a project in the UI, generate a token under My Account, then from the repository:

sonar-scanner \
  -Dsonar.projectKey=my-app \
  -Dsonar.sources=. \
  -Dsonar.host.url=http://sonarqube:9000 \
  -Dsonar.token=$SONAR_TOKEN \
  -Dsonar.qualitygate.wait=true

Maven and Gradle have plugins that replace the CLI, and the sonarsource/sonar-scanner-cli image is the easy way to run it as a step in Woodpecker CI or any other runner in the CI/CD category. sonar.qualitygate.wait=true makes the scanner block until the server has evaluated the gate and exit non-zero if it fails. That single flag is the feature: without it, SonarQube is a dashboard people stop opening. With it, a pull request that adds an unhandled SQL injection or drops coverage below your threshold does not merge.

What the free edition gives you and what it withholds

Free covers bug and vulnerability detection, code smells, duplication, coverage import from your test runner, quality gates and profiles, and analysis for roughly 30 languages including Java, JavaScript and TypeScript, Python, Go, PHP, C#, Kotlin, and Ruby. That is most of the product for most teams.

Withheld to the Developer Edition and above: analysis of branches other than the main one, pull request decoration in GitHub, GitLab, and Bitbucket, C and C++ support, and the deeper taint-tracking security rules. A community-maintained branch plugin exists that restores branch and PR analysis in the free build, and plenty of self-hosters run it, with the caveat that it is third-party and has broken on major upgrades before. If you host your code on Gitea or Forgejo, the free edition's lack of native PR decoration matters less, because there is none for those forges in the paid editions either; the quality gate exit code in CI does the job instead. My notes on the forges themselves are in the self-hosted git forges piece.

When a linter in CI is enough

For 1 person on 3 repositories, SonarQube is 2 GB of RAM to be told what ruff, eslint, or golangci-lint would have told you in a 20-second CI step. Its value appears with a team: a shared definition of "good enough", a history that shows whether the codebase is getting better, and a gate that nobody has to argue about in review. It also catches a category of security defect, data flowing from a request parameter into a query or a shell, that plain linters do not attempt; the limits of asking a language model to do that instead are covered in AI code review limits.

What I'd do

Two or more developers and a CI pipeline: SonarQube Community on a 4 GB VM with Postgres, vm.max_map_count set before the first docker compose up, the quality gate wired in with qualitygate.wait=true, and the container stopped overnight if RAM is tight. Solo, or fewer than 5 repositories: linters in CI, and revisit SonarQube the day someone else starts merging into your code.

Compare SonarQube

8 head-to-head comparisons.

Similar developer tools & git apps