---
# === IDENTITY ===
id: software/devops/docker-sonarqube/2026
canonical_question: "Docker Compose reference: SonarQube"
aliases:
  - "SonarQube Docker Compose setup"
  - "docker-compose sonarqube postgresql"
  - "sonarqube docker production deployment"
  - "self-hosted sonarqube docker"
  - "sonarqube container setup with postgres"
  - "run sonarqube in docker"
  - "sonarqube docker-compose.yml example"
  - "sonarqube CI/CD docker integration"
entity_type: software_reference
domain: software > devops > Docker SonarQube
region: global
jurisdiction: global
temporal_scope: 2025-2026

# === VERIFICATION ===
last_verified: 2026-02-27
confidence: 0.93
version: 1.0
first_published: 2026-02-27

# === TEMPORAL VALIDITY ===
temporal_validity:
  status: stable
  last_breaking_change: "SonarQube 2025.1 LTA introduced new versioning scheme (year-based); read_only filesystem and tmpfs mounts added to official compose examples"
  next_review: 2026-08-26
  change_sensitivity: medium

# === CONSTRAINTS ===
constraints:
  - "Host kernel MUST have vm.max_map_count >= 524288 and fs.file-max >= 131072 -- SonarQube's embedded Elasticsearch will fail to start otherwise"
  - "Use Docker named volumes, NOT bind mounts -- bind mounts prevent plugins from populating correctly"
  - "PostgreSQL is the only supported production database -- H2 is for evaluation only and does not support upgrading"
  - "SonarQube Community Edition is free; Developer, Enterprise, and Data Center editions require a commercial license"
  - "Default admin credentials (admin/admin) MUST be changed immediately after first login"
  - "Docker Engine 20.10+ is required; amd64 and arm64 architectures are supported"

# === SKIP CONDITIONS ===
skip_this_unit_if:
  - condition: "Need SonarQube Cloud (hosted SaaS) setup, not self-hosted"
    use_instead: "SonarQube Cloud documentation at docs.sonarsource.com/sonarqube-cloud"
  - condition: "Need bare-metal or VM installation without Docker"
    use_instead: "SonarQube Server installation docs (non-Docker)"
  - condition: "Need SonarLint IDE integration only"
    use_instead: "SonarLint documentation at docs.sonarsource.com/sonarlint"

# === AGENT HINTS ===
inputs_needed:
  - key: "edition"
    question: "Which SonarQube edition do you need?"
    type: choice
    options: ["Community (free)", "Developer", "Enterprise", "Data Center"]
  - key: "ci_platform"
    question: "Which CI/CD platform will run the scanner?"
    type: choice
    options: ["GitHub Actions", "GitLab CI", "Jenkins", "Azure DevOps", "Manual/CLI"]

# === DISTRIBUTION ===
canonical_source: "https://knowledgelib.io/software/devops/docker-sonarqube/2026"
suggested_citation: "Source: knowledgelib.io -- AI Knowledge Library (verified 2026-02-27)"

# === RELATED UNITS ===
related_kos:
  depends_on: []
  related_to:
    - id: "software/devops/docker-compose-reference/2026"
      label: "Docker Compose Reference"
  solves: []
  alternative_to: []
  often_confused_with: []

# === SOURCES (7 authoritative sources) ===
# Types: official_docs, technical_blog, rfc_spec, academic_paper, community_resource, industry_report
# Reliability: high, moderate_high, moderate, moderate_low, low, authoritative
sources:
  - id: src1
    title: "Installing SonarQube from the Docker image"
    author: SonarSource
    url: https://docs.sonarsource.com/sonarqube-server/2025.1/setup-and-upgrade/install-the-server/installing-sonarqube-from-docker
    type: official_docs
    published: 2025-06-01
    reliability: authoritative
  - id: src2
    title: "docker-sonarqube: Official SonarQube Docker Repository"
    author: SonarSource
    url: https://github.com/SonarSource/docker-sonarqube
    type: official_docs
    published: 2025-12-01
    reliability: authoritative
  - id: src3
    title: "SonarQube Official Docker Hub Image"
    author: SonarSource
    url: https://hub.docker.com/_/sonarqube
    type: official_docs
    published: 2025-12-01
    reliability: authoritative
  - id: src4
    title: "Quality Gates Documentation"
    author: SonarSource
    url: https://docs.sonarsource.com/sonarqube-server/10.8/instance-administration/analysis-functions/quality-gates
    type: official_docs
    published: 2025-06-01
    reliability: authoritative
  - id: src5
    title: "SonarQube Pre-installation Requirements (Linux)"
    author: SonarSource
    url: https://docs.sonarsource.com/sonarqube-server/10.8/setup-and-upgrade/pre-installation/linux
    type: official_docs
    published: 2025-06-01
    reliability: authoritative
  - id: src6
    title: "SonarScanner CLI Docker in GitHub Actions"
    author: Jonathan Medd
    url: https://www.jonathanmedd.net/2024/03/sonarscanner-cli-docker-in-github-actions.html/
    type: technical_blog
    published: 2024-03-15
    reliability: moderate_high
  - id: src7
    title: "Integrating SonarQube with GitLab CI/CD -- A Complete Guide"
    author: Jawaharsaravanan
    url: https://medium.com/@jawaharsaravanan123/integrating-sonarqube-with-gitlab-ci-cd-a-complete-guide-bf4030405ad5
    type: technical_blog
    published: 2024-08-01
    reliability: moderate_high
---

# Docker Compose Reference: SonarQube

## TL;DR

- **Bottom line**: SonarQube runs as two Docker services (SonarQube + PostgreSQL) with named volumes for persistence, requiring host kernel tuning (vm.max_map_count >= 524288) before startup.
- **Key tool/command**: `docker compose up -d` with a compose file defining `sonarqube:community` (or `developer`/`enterprise`) and `postgres:17` services.
- **Watch out for**: Using bind mounts instead of named volumes breaks plugin installation, and forgetting to set `vm.max_map_count` on the Docker host causes Elasticsearch to crash on startup.
- **Works with**: Docker Engine 20.10+, amd64/arm64. PostgreSQL 15-17. SonarQube Community (free), Developer, Enterprise, Data Center editions.

## Constraints
<!-- Agents: read this section before recommending any action from this unit.
     These are hard constraints that must not be violated. -->

- Host kernel MUST have `vm.max_map_count >= 524288` and `fs.file-max >= 131072` -- SonarQube's embedded Elasticsearch will fail to start otherwise
- Use Docker named volumes, NOT bind mounts -- bind mounts prevent plugins from populating correctly
- PostgreSQL is the only supported production database -- H2 is for evaluation only and does not support upgrading
- SonarQube Community Edition is free; Developer, Enterprise, and Data Center editions require a commercial license
- Default admin credentials (admin/admin) MUST be changed immediately after first login
- Docker Engine 20.10+ is required; amd64 and arm64 architectures are supported

## Quick Reference

| Service | Image | Ports | Volumes | Key Env |
|---|---|---|---|---|
| sonarqube | `sonarqube:community` | `9000:9000` | `sonarqube_data:/opt/sonarqube/data` | `SONAR_JDBC_URL=jdbc:postgresql://db:5432/sonar` |
| sonarqube | `sonarqube:developer` | `9000:9000` | `sonarqube_extensions:/opt/sonarqube/extensions` | `SONAR_JDBC_USERNAME=sonar` |
| sonarqube | `sonarqube:enterprise` | `9000:9000` | `sonarqube_logs:/opt/sonarqube/logs` | `SONAR_JDBC_PASSWORD=sonar` |
| postgresql | `postgres:17` | `5432` (internal) | `postgresql_data:/var/lib/postgresql/data` | `POSTGRES_USER=sonar` |
| postgresql | `postgres:16` | `5432` (internal) | (same) | `POSTGRES_PASSWORD=sonar` |
| postgresql | `postgres:15` | `5432` (internal) | (same) | `POSTGRES_DB=sonar` |
| sonar-scanner | `sonarsource/sonar-scanner-cli:11` | none | `/usr/src` (mount code) | `SONAR_HOST_URL`, `SONAR_TOKEN` |
| sonarqube (tmpfs) | (any edition) | -- | `sonarqube_temp:/opt/sonarqube/temp` | `tmpfs: /tmp` (256M) |

**Edition Comparison:**

| Feature | Community (Free) | Developer | Enterprise | Data Center |
|---|---|---|---|---|
| Languages | 17+ (Java, JS, Python, C#, etc.) | 30+ (incl. C, C++, Obj-C, Swift, ABAP) | 30+ | 30+ |
| Branch analysis | No | Yes | Yes | Yes |
| Pull request decoration | No | Yes (GitHub, GitLab, Azure, Bitbucket) | Yes | Yes |
| Portfolio management | No | No | Yes | Yes |
| High availability | No | No | No | Yes |
| Docker image tag | `sonarqube:community` | `sonarqube:developer` | `sonarqube:enterprise` | `sonarqube:datacenter-app` + `datacenter-search` |
| Price | Free (LGPL v3) | Commercial license | Commercial license | Commercial license |

## Decision Tree

```
START: What SonarQube Docker setup do you need?
+-- Need quick local evaluation?
|   +-- YES -> Use `sonarqube:community` with embedded H2 (no PostgreSQL needed)
|   +-- NO (production) |
+-- Single instance or high availability?
|   +-- Single instance |
|   |   +-- Need branch analysis / PR decoration?
|   |   |   +-- YES -> Use `sonarqube:developer` + PostgreSQL
|   |   |   +-- NO -> Use `sonarqube:community` + PostgreSQL
|   |   +-- How many projects?
|   |       +-- < 50 projects -> 4 GB RAM, 2 CPU cores
|   |       +-- 50-200 projects -> 8 GB RAM, 4 CPU cores
|   |       +-- > 200 projects -> Consider Enterprise edition
|   +-- High availability -> Use Data Center edition (datacenter-app + datacenter-search)
+-- CI/CD integration?
    +-- GitHub Actions -> Use `sonarsource/sonarqube-scan-action`
    +-- GitLab CI -> Use `sonarsource/sonar-scanner-cli:11` image
    +-- Jenkins -> Use SonarQube Scanner for Jenkins plugin
    +-- CLI/Manual -> Use `sonar-scanner` CLI or Docker image
```

## Step-by-Step Guide

### 1. Configure host kernel parameters

SonarQube embeds Elasticsearch, which requires specific Linux kernel settings. These must be set on the Docker host, not inside the container. [src5]

```bash
# Set temporarily (resets on reboot)
sudo sysctl -w vm.max_map_count=524288
sudo sysctl -w fs.file-max=131072

# Set permanently (survives reboot)
echo "vm.max_map_count=524288" | sudo tee -a /etc/sysctl.d/99-sonarqube.conf
echo "fs.file-max=131072" | sudo tee -a /etc/sysctl.d/99-sonarqube.conf
sudo sysctl --system
```

**Verify**: `sysctl vm.max_map_count` -> expected output: `vm.max_map_count = 524288`

### 2. Create docker-compose.yml

Create the compose file with SonarQube and PostgreSQL services. Use named volumes, not bind mounts. [src1] [src2]

```yaml
# docker-compose.yml -- SonarQube with PostgreSQL
# Usage: docker compose up -d
services:
  sonarqube:
    image: sonarqube:community  # or :developer, :enterprise
    hostname: sonarqube
    read_only: true
    depends_on:
      db:
        condition: service_healthy
    environment:
      SONAR_JDBC_URL: jdbc:postgresql://db:5432/sonar
      SONAR_JDBC_USERNAME: sonar
      SONAR_JDBC_PASSWORD: ${SONAR_DB_PASSWORD:-sonar}
    volumes:
      - sonarqube_data:/opt/sonarqube/data
      - sonarqube_extensions:/opt/sonarqube/extensions
      - sonarqube_logs:/opt/sonarqube/logs
      - sonarqube_temp:/opt/sonarqube/temp
    tmpfs:
      - /tmp:size=256m
    ports:
      - "9000:9000"
    networks:
      - sonarnet

  db:
    image: postgres:17
    hostname: postgresql
    environment:
      POSTGRES_USER: sonar
      POSTGRES_PASSWORD: ${SONAR_DB_PASSWORD:-sonar}
      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
    networks:
      - sonarnet

volumes:
  sonarqube_data:
  sonarqube_extensions:
  sonarqube_logs:
  sonarqube_temp:
  postgresql_data:

networks:
  sonarnet:
    driver: bridge
```

**Verify**: `docker compose config` -> no errors in output

### 3. Start the services

Launch SonarQube and wait for it to become healthy. First startup takes 1-3 minutes as the database schema is created. [src1]

```bash
# Start in detached mode
docker compose up -d

# Watch startup logs
docker compose logs -f sonarqube

# Wait for "SonarQube is operational" message
```

**Verify**: `curl -s http://localhost:9000/api/system/status | jq .status` -> expected output: `"UP"`

### 4. Change default admin password

The default credentials are admin/admin. Change the password immediately after first login. [src1]

```bash
# Change admin password via API
curl -u admin:admin -X POST \
  "http://localhost:9000/api/users/change_password" \
  -d "login=admin&previousPassword=admin&password=YOUR_SECURE_PASSWORD"
```

**Verify**: `curl -u admin:YOUR_SECURE_PASSWORD http://localhost:9000/api/system/status` -> returns `200 OK`

### 5. Create a project and generate a token

Create a project and generate an authentication token for the scanner. [src4]

```bash
# Generate a user token for CI/CD
curl -u admin:YOUR_SECURE_PASSWORD -X POST \
  "http://localhost:9000/api/user_tokens/generate" \
  -d "name=ci-scanner&type=GLOBAL_ANALYSIS_TOKEN"
# Save the returned token value -- it cannot be retrieved again
```

**Verify**: Navigate to `http://localhost:9000/account/security` -> token appears in list

### 6. Configure sonar-project.properties

Place this file in your project root to configure the scanner. [src1]

```properties
# sonar-project.properties
sonar.projectKey=my-project
sonar.projectName=My Project
sonar.sources=src
sonar.tests=test
sonar.sourceEncoding=UTF-8

# Quality gate -- block CI if gate fails
sonar.qualitygate.wait=true
sonar.qualitygate.timeout=300

# Language-specific settings (examples)
# sonar.java.binaries=target/classes
# sonar.javascript.lcov.reportPaths=coverage/lcov.info
# sonar.python.coverage.reportPaths=coverage.xml
```

**Verify**: File exists at project root: `ls sonar-project.properties`

### 7. Run SonarScanner

Run the scanner against your project using Docker. [src6]

```bash
# Run sonar-scanner using Docker
docker run --rm \
  --network=sonarnet \
  -e SONAR_HOST_URL="http://sonarqube:9000" \
  -e SONAR_TOKEN="your_generated_token" \
  -v "$(pwd):/usr/src" \
  sonarsource/sonar-scanner-cli:11

# Or install sonar-scanner locally via npm
npm install -g sonar-scanner
sonar-scanner \
  -Dsonar.host.url=http://localhost:9000 \
  -Dsonar.token=your_generated_token
```

**Verify**: Check `http://localhost:9000/dashboard?id=my-project` -> analysis results appear

## Code Examples

### GitHub Actions: SonarQube Analysis

> Full script: [github-actions-sonarqube-analysis.yml](scripts/github-actions-sonarqube-analysis.yml) (26 lines)

```yaml
# .github/workflows/sonarqube.yml
# Input:  Push/PR to repository with sonar-project.properties
# Output: SonarQube analysis results, quality gate status check
name: SonarQube Analysis
on:
# ... (see full script)
```

### GitLab CI: SonarQube Analysis

```yaml
# .gitlab-ci.yml
# Input:  Push/MR to GitLab repository
# Output: SonarQube analysis with MR decoration (Developer+ edition)

sonarqube-check:
  image:
    name: sonarsource/sonar-scanner-cli:11
    entrypoint: [""]
  variables:
    SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar"
    GIT_DEPTH: "0"
  cache:
    key: "${CI_JOB_NAME}"
    paths:
      - .sonar/cache
  script:
    - sonar-scanner
      -Dsonar.host.url=${SONAR_HOST_URL}
      -Dsonar.token=${SONAR_TOKEN}
      -Dsonar.projectKey=${CI_PROJECT_PATH_SLUG}
      -Dsonar.qualitygate.wait=true
  allow_failure: false
  rules:
    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
```

### Docker Compose: Production Hardened Setup

> Full script: [docker-compose-production.yml](scripts/docker-compose-production.yml) (62 lines)

```yaml
# Production-hardened docker-compose.yml with resource limits,
# health checks, restart policies, and reverse proxy readiness.
# See full script for complete configuration.
services:
  sonarqube:
    image: sonarqube:developer
    read_only: true
    deploy:
      resources:
        limits: { memory: 4g, cpus: "2.0" }
        reservations: { memory: 2g }
    # ... (see full script for all settings)
```

### Bash: Backup SonarQube Data

```bash
#!/bin/bash
# Input:  Running SonarQube Docker Compose stack
# Output: Timestamped backup of PostgreSQL database and SonarQube volumes

BACKUP_DIR="./backups/$(date +%Y%m%d_%H%M%S)"
mkdir -p "$BACKUP_DIR"

# Backup PostgreSQL database
docker compose exec -T db pg_dump -U sonar sonar \
  | gzip > "$BACKUP_DIR/sonar_db.sql.gz"

# Backup SonarQube extensions (plugins)
docker run --rm \
  -v sonarqube_extensions:/data \
  -v "$(pwd)/$BACKUP_DIR":/backup \
  alpine tar czf /backup/extensions.tar.gz -C /data .

echo "Backup saved to $BACKUP_DIR"
```

## Anti-Patterns

### Wrong: Using bind mounts for SonarQube volumes

```yaml
# BAD -- bind mounts prevent plugins from populating correctly
services:
  sonarqube:
    image: sonarqube:community
    volumes:
      - ./sonarqube/data:/opt/sonarqube/data
      - ./sonarqube/extensions:/opt/sonarqube/extensions
      - ./sonarqube/logs:/opt/sonarqube/logs
```

### Correct: Using named Docker volumes

```yaml
# GOOD -- named volumes let SonarQube populate plugin directories correctly
services:
  sonarqube:
    image: sonarqube:community
    volumes:
      - sonarqube_data:/opt/sonarqube/data
      - sonarqube_extensions:/opt/sonarqube/extensions
      - sonarqube_logs:/opt/sonarqube/logs

volumes:
  sonarqube_data:
  sonarqube_extensions:
  sonarqube_logs:
```

### Wrong: Skipping PostgreSQL health check

```yaml
# BAD -- SonarQube starts before PostgreSQL is ready, causing JDBC connection errors
services:
  sonarqube:
    image: sonarqube:community
    depends_on:
      - db  # only waits for container start, not database readiness
```

### Correct: Using health check with condition

```yaml
# GOOD -- SonarQube waits until PostgreSQL passes health check
services:
  sonarqube:
    image: sonarqube:community
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:17
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U sonar -d sonar"]
      interval: 10s
      timeout: 5s
      retries: 5
```

### Wrong: Using H2 database in production

```yaml
# BAD -- H2 is for evaluation only, data loss risk, no upgrade path
services:
  sonarqube:
    image: sonarqube:community
    # No SONAR_JDBC_URL = uses embedded H2
    ports:
      - "9000:9000"
```

### Correct: Always use PostgreSQL for production

```yaml
# GOOD -- PostgreSQL provides durability, upgradability, and concurrent access
services:
  sonarqube:
    image: sonarqube:community
    environment:
      SONAR_JDBC_URL: jdbc:postgresql://db:5432/sonar
      SONAR_JDBC_USERNAME: sonar
      SONAR_JDBC_PASSWORD: ${SONAR_DB_PASSWORD}
    depends_on:
      db:
        condition: service_healthy
```

### Wrong: Hardcoding secrets in docker-compose.yml

```yaml
# BAD -- secrets committed to version control
services:
  sonarqube:
    environment:
      SONAR_JDBC_PASSWORD: my_secret_password_123
```

### Correct: Using environment variables or Docker secrets

```yaml
# GOOD -- use .env file or Docker secrets
services:
  sonarqube:
    environment:
      SONAR_JDBC_PASSWORD: ${SONAR_DB_PASSWORD}
    # Or with Docker secrets (Swarm mode):
    # secrets:
    #   - sonar_db_password

# .env file (not committed to git):
# SONAR_DB_PASSWORD=your_secure_password
```

## Common Pitfalls

- **vm.max_map_count not set**: SonarQube crashes on startup with `max virtual memory areas vm.max_map_count [65530] is too low`. Fix: `sudo sysctl -w vm.max_map_count=524288` on the Docker host. This is a host-level setting, not a container setting. [src5]
- **Elasticsearch bootstrap checks fail**: Container exits immediately with `bootstrap checks failed`. Fix: Set `vm.max_map_count`, `fs.file-max`, and ulimits on the host system before starting the container. [src5]
- **Plugins not loading after restart**: Using bind mounts instead of named volumes prevents SonarQube from populating the extensions directory. Fix: Switch to named volumes in docker-compose.yml. [src1]
- **JDBC connection refused on startup**: SonarQube starts before PostgreSQL is ready. Fix: Add `healthcheck` to the PostgreSQL service and `depends_on: { db: { condition: service_healthy } }` to SonarQube. [src2]
- **Quality gate timeout in CI**: `sonar.qualitygate.wait=true` hangs indefinitely. Fix: Add `sonar.qualitygate.timeout=300` (seconds) to set an upper bound. [src4]
- **Scanner cannot reach SonarQube in Docker network**: Scanner running on host uses `localhost:9000`, but SonarQube is on the Docker bridge network. Fix: When running scanner in Docker, use the container hostname (`http://sonarqube:9000`) and attach to the same Docker network. [src6]
- **Data lost after `docker compose down -v`**: The `-v` flag removes named volumes. Fix: Use `docker compose down` without `-v` to preserve data. Create regular backups of the PostgreSQL database. [src1]
- **Out of memory on large projects**: SonarQube's default JVM heap is insufficient for large codebases. Fix: Set `SONAR_WEB_JAVAOPTS=-Xmx2g` and `SONAR_CE_JAVAOPTS=-Xmx2g` environment variables. [src3]

## Diagnostic Commands

```bash
# Check SonarQube service status
curl -s http://localhost:9000/api/system/status | jq .

# Check SonarQube version
curl -s http://localhost:9000/api/system/info -u admin:password | jq .System.Version

# View SonarQube logs
docker compose logs sonarqube --tail=100

# Check Elasticsearch status (embedded)
docker compose exec sonarqube curl -s http://localhost:9001/_cluster/health | jq .

# Check PostgreSQL connectivity from SonarQube container
docker compose exec sonarqube bash -c 'echo "SELECT 1;" | psql "jdbc:postgresql://db:5432/sonar"' 2>/dev/null || echo "Use pg_isready on db container instead"
docker compose exec db pg_isready -U sonar -d sonar

# Check host kernel parameters
sysctl vm.max_map_count fs.file-max

# Verify volumes exist and have data
docker volume ls | grep sonar
docker volume inspect sonarqube_data

# Check resource usage
docker compose stats --no-stream

# List installed plugins
curl -s http://localhost:9000/api/plugins/installed -u admin:password | jq '.plugins[].key'

# Check quality gate status for a project
curl -s "http://localhost:9000/api/qualitygates/project_status?projectKey=my-project" \
  -u admin:password | jq .projectStatus.status
```

## Version History & Compatibility

| Version | Status | Breaking Changes | Migration Notes |
|---|---|---|---|
| 2025.1 LTA | Current LTA | New year-based versioning scheme; dropped MySQL/MSSQL support in earlier versions | Upgrade from 9.9 LTS requires intermediate step via 10.x |
| 10.8 | Current (non-LTA) | read_only filesystem in official compose example | Update compose file to include tmpfs and temp volume |
| 10.7 | Maintained | None | Direct upgrade from 10.6 supported |
| 10.6 | Previous | Changed default branch analysis behavior | Review branch configuration after upgrade |
| 9.9 LTS | End of life (2025) | -- | Must upgrade to 10.x first, then to 2025.1 LTA |
| 8.9 LTS | End of life | Dropped support for Oracle 11g, IE11 | Must upgrade to 9.9 LTS first |

**PostgreSQL Compatibility:**

| PostgreSQL | SonarQube 10.x | SonarQube 2025.1 LTA |
|---|---|---|
| PostgreSQL 17 | Supported | Supported |
| PostgreSQL 16 | Supported | Supported |
| PostgreSQL 15 | Supported | Supported |
| PostgreSQL 14 | Supported | Supported |
| PostgreSQL 13 | Supported | Supported (minimum) |
| PostgreSQL 12 | Deprecated | Not supported |

## When to Use / When Not to Use

| Use When | Don't Use When | Use Instead |
|---|---|---|
| Self-hosting SonarQube for code quality analysis | Team prefers managed SaaS | SonarQube Cloud (sonarcloud.io) |
| Need full control over data and configuration | Quick one-time code scan without infrastructure | SonarLint IDE plugin |
| CI/CD pipeline needs automated quality gates | Only need linting without security analysis | ESLint, Pylint, or language-specific linters |
| Organization requires air-gapped/on-premise deployment | Budget constraints and < 5 developers | SonarQube Cloud free tier |
| Need branch analysis and PR decoration (Developer+) | Only scanning a single branch | Community edition may suffice |
| High availability required (Data Center edition) | Single team, < 100 projects | Developer or Enterprise edition |

## Important Caveats

- SonarQube Community Edition is licensed under LGPL v3; Developer/Enterprise/Data Center require commercial licenses from SonarSource
- The embedded Elasticsearch instance means SonarQube has significant memory requirements (minimum 2 GB RAM, 4+ GB recommended for production)
- Docker Desktop on macOS/Windows handles `vm.max_map_count` automatically via its Linux VM, but native Linux Docker hosts require manual configuration
- SonarQube does not support downgrades -- always backup before upgrading and test in a staging environment first
- The `sonar-scanner-cli` Docker image expects code mounted at `/usr/src`; GitLab CI mounts at `$CI_PROJECT_DIR`, so set `SONAR_PROJECT_BASE_DIR=$CI_PROJECT_DIR`
- Quality gate results are only available after the background task (Compute Engine) completes, which may take minutes on large projects

## Related Units
<!-- Generated from related_kos frontmatter -->

- [Docker Compose Reference](/software/devops/docker-compose-reference/2026)
