Local SonarQube + .NET! Catch Bugs Before They Catch You!!!

Local SonarQube + .NET! Catch Bugs Before They Catch You!!!
Photo by Gabriel Heinzer / Unsplash

If you’ve been coding in C# for a while, you’ve probably run into that dreaded moment during a pull request:

“Hey, can you add unit tests?”
“Why are there magic strings?”
“You missed a null check here…”

Wouldn’t it be nice if a robot pointed out those things before your teammates did? Enter SonarQube, a fantastic tool for static analysis and continuous inspection of your codebase.

Today, we’ll cover:

  • Running SonarQube locally with Docker Compose
  • Setting up a manual project in SonarQube UI
  • Using .NET CLI (dotnet sonarscanner) to analyze your project with dotnet build
  • Integration tips for Visual Studio and VS Code
  • Bonus: Running SonarQube on your HomeLab Raspberry Pi
  • PowerShell alias trick + NTFY push notifications

Docker Compose for SonarQube

Create a file named docker-compose.yml:

version: "3.9"

services:
  sonarqube:
    image: sonarqube:latest
    container_name: sonarqube
    ports:
      - "9000:9000"
    environment:
      SONAR_ES_BOOTSTRAP_CHECKS_DISABLE: "true"
    volumes:
      - sonarqube_data:/opt/sonarqube/data
      - sonarqube_logs:/opt/sonarqube/logs
      - sonarqube_extensions:/opt/sonarqube/extensions

  db:
    image: postgres:15
    environment:
      POSTGRES_USER: sonar
      POSTGRES_PASSWORD: sonar
      POSTGRES_DB: sonarqube
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  sonarqube_data:
  sonarqube_logs:
  sonarqube_extensions:
  postgres_data:

Run it with:

docker compose up -d

Open http://localhost:9000, login with admin/admin (and change the password!).


Setting Up a Manual Project in SonarQube

Inside the SonarQube dashboard:

Go to Projects → Create Project.

Choose Manually.

Enter your project name, e.g., MyDotnetApp.

Generate a project token — copy it, we’ll use it shortly.

That’s it — SonarQube is ready to accept scans.


Wiring the CLI with .NET Build

Install the scanner:

dotnet tool install --global dotnet-sonarscanner

Navigate to your solution folder and run:

dotnet sonarscanner begin `
  /k:"MyDotnetApp" `
  /d:sonar.login="YOUR_PROJECT_TOKEN" `
  /d:sonar.host.url="http://localhost:9000"

dotnet build

dotnet sonarscanner end /d:sonar.login="YOUR_PROJECT_TOKEN"

Head back to the SonarQube dashboard, and you’ll see metrics: code smells, security hotspots, duplicated code, and more.


Visual Studio & VS Code Integration

Visual Studio: Install the SonarLint extension, connect to SonarQube, and bind your solution.

VS Code: Install the SonarLint extension, run “SonarLint: Connect to SonarQube” from the command palette, and bind your workspace.

Both editors now show SonarQube issues live as you type — the same rules as the server.


Bonus: Running SonarQube in a HomeLab (Raspberry Pi)

If you’re into tinkering (and I know many of you are), you don’t need to keep SonarQube tied to localhost.

With a HomeLab setup — for example, running Docker on a Raspberry Pi 5 — you can deploy SonarQube to your Pi and let it serve all your devices.

Adjust the sonar.host.url in your CLI calls from http://localhost:9000 to http://raspberrypi.local:9000 (or the Pi’s IP).

Point VS Code and Visual Studio SonarLint plugins at the same URL.

Now your entire dev environment, laptops, and even teammates at home can connect to a single persistent SonarQube instance.

This is especially handy if you’re already running other services on your Pi (Git, Pi-hole, Grafana dashboards). SonarQube fits right into that ecosystem.


Gotchas & Tips

Performance: The first scan will always be slower — the cache speeds things up afterward.

Resource Needs: On Raspberry Pi, give SonarQube enough swap/memory; otherwise it might refuse to start.

CI/CD: Once stable, integrate with GitHub Actions or Azure DevOps to enforce quality gates.

CLI Aliases in PowerShell: Tired of typing the whole scanner command every time? Create a simple alias in your PowerShell profile so you can just type sonar-scan.

PowerShell Alias with Raspberry Pi Support + NTFY Notification

# Alias to wrap SonarScanner for .NET with default parameters
function sonar-scan {
    param(
        [string]$ProjectKey = "MyDotnetApp",
        [string]$Version = "1.0.0",
        [switch]$UsePi,     # toggle if you want to target Raspberry Pi instance
        [string]$NotifyUrl = "https://ntfy.sh/my-sonarqube"  # replace with your ntfy topic
    )

    $url = "http://localhost:9000"
    if ($UsePi) {
        # Change raspberrypi.local to your Pi's hostname or IP
        $url = "http://raspberrypi.local:9000"
    }

    try {
        dotnet sonarscanner begin `
          /k:$ProjectKey `
          /v:$Version `
          /d:sonar.host.url=$url `
          /d:sonar.login="YOUR_PROJECT_TOKEN"

        dotnet build

        dotnet sonarscanner end /d:sonar.login="YOUR_PROJECT_TOKEN"

        # Send NTFY success notification
        Invoke-RestMethod -Uri $NotifyUrl -Method POST -Body "✅ SonarQube scan finished successfully for $ProjectKey v$Version"
    }
    catch {
        # Send NTFY failure notification
        Invoke-RestMethod -Uri $NotifyUrl -Method POST -Body "❌ SonarQube scan FAILED for $ProjectKey v$Version"
        throw
    }
}

You can use NTFY to tell you when it is done, you can follow the setup in this post:

NTFY, not a typo, awesome tool for push notifications.
This is going to be a short post. NTFY, is a tool to send push notifications, specially to mobile. Why would you like to use this tool? Use cases that I can think of but not limited are Check if a site is downA long running task is doneA task

Usage:

# Localhost scan
sonar-scan -ProjectKey "MyDotnetApp" -Version "1.2.3"

# Raspberry Pi HomeLab scan + notification
sonar-scan -ProjectKey "MyDotnetApp" -Version "1.2.3" -UsePi

Every time the scan finishes, your phone buzzes with a push notification — no more babysitting builds. 🚀


Architecture Flow (C4 Diagram)

@startuml
!include <C4/C4_Context>

title SonarQube + .NET Quality Flow

Person(dev, "Developer", "Writes C# code")
System_Ext(ide, "IDE (VS / VS Code)", "Editor with SonarLint plugin")
System_Boundary(local, "HomeLab or Local Machine") {
  System(cli, "dotnet sonarscanner", "Analyzes code during build")
  SystemDb(sq, "SonarQube", "Code quality dashboard & analysis engine")
}

Rel(dev, cli, "Runs `dotnet sonarscanner`")
Rel(cli, sq, "Sends analysis results")
Rel(sq, ide, "Sync rules & issues via SonarLint")
Rel(dev, ide, "Fix issues highlighted in-editor")

' Optional Raspberry Pi home lab representation
System_Ext(pi, "Raspberry Pi (HomeLab)", "Runs SonarQube via Docker")
Rel(cli, pi, "Alternative target for scans")

@enduml

This shows how a developer uses the CLI scanner, results go to SonarQube (local or Pi), and IDE plugins pull down the same rules/issues.


Conclusion

With Docker Compose on your laptop or a Raspberry Pi in your HomeLab, SonarQube becomes a personal code quality dashboard. Add the IDE integrations, the PowerShell alias, and push notifications, and you’ve got a smooth, developer-friendly workflow that keeps your codebase healthy before it ever hits a pull request.

Happy coding!!!