Von Swagger UI zu Scalar: Praktischer Einstieg für .NET APIs
Swagger UI hat sich als Standard für interaktive API-Dokumentation in .NET etabliert. Viele Teams kennen das Muster: Swashbuckle einbinden, app.UseSwaggerUI() aufrufen, fertig. Was dann kommt, ist eine funktionale, aber in die Jahre gekommene Oberfläche ohne zentrales Hosting, ohne Team-Features und mit einer UX, die man eher toleriert als schätzt.
Scalar ist eine Open-Source-Alternative, die denselben OpenAPI-Standard nutzt, aber konsequent neu gedacht hat, wie API-Dokumentation aussehen und funktionieren sollte. Dieser Artikel zeigt dir alles von der lokalen Einbindung in Swashbuckle über OAuth2-Konfiguration bis zum automatisierten Push in die Scalar Registry aus einer CI-Pipeline.
Scalar im Überblick
Scalar ist ein Open-Source OpenAPI-Viewer (MIT-Lizenz). Es liest jede swagger.json oder openapi.json und rendert daraus eine interaktive Oberfläche mit Dark Mode, Sidebar-Navigation, Volltextsuche und einem integrierten API-Client, mit dem Requests direkt im Browser abgesendet werden können.
Der sichtbarste Unterschied zu Swagger UI ist die Oberfläche selbst: moderner, lesbarer, strukturierter. Darüber hinaus bietet die Scalar-Plattform als SaaS-Produkt eine zentrale Registry für API-Dokumentationen. Teams können ihre OpenAPI-Dateien per CLI oder CI-Pipeline pushen und erhalten eine gehostete, versionierte Ansicht für alle APIs des Unternehmens.
Das Open-Source-Kernpaket Scalar.AspNetCore ist MIT-lizenziert und kostenlos. Die Scalar CLI für den Push ist ebenfalls kostenlos. Öffentliche APIs können kostenfrei in der Registry gehostet werden und das Self-Hosting des Scalar UI ist immer kostenlos.
Kostenpflichtig sind Private Registries (nicht öffentlich zugängliche Docs), SSO- (Single Sign-On) und SCIM-Integration (automatische Nutzerprovisionierung), Team Seats, Custom Branding mit eigener Domain, Analytics und Advanced Access Controls wie IP Allowlists oder rollenbasierte Zugriffssteuerung.
Da sich SaaS-Preismodelle ändern können, solltest du die aktuelle Übersicht immer direkt auf scalar.com/pricing prüfen.

Minimale Integration in .NET
Voraussetzung ist ein bestehendes ASP.NET Core Projekt mit Swashbuckle (Swashbuckle.AspNetCore), NSwag (NSwag.AspNetCore) oder der Microsoft.AspNetCore.OpenApi-Bibliothek (die es seit .NET 9 gibt), welches eine swagger.json bereitstellt. Das NuGet-Paket Scalar.AspNetCore wird direkt zum Projekt hinzugefügt:
dotnet add package Scalar.AspNetCore
Danach reichen wenige Zeilen in Program.cs, um Scalar lokal zu aktivieren. Scalar liest die lokal gehostete OpenAPI-Datei und stellt die Oberfläche unter /scalar bereit:
// Program.cs – Scalar in ein bestehendes Swashbuckle-Projekt einbinden
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
app.UseSwagger(); // Erzeugt /swagger/v1/swagger.json
app.MapScalarApiReference(options =>
{
options.WithOpenApiRoutePattern("/swagger/v1/swagger.json");
options.WithTitle("My API");
});
Bei NSwag und Microsoft OpenAPI wird app.UseOpenApi() statt app.UseSwagger() verwendet.
Die offizielle .NET-Integrationsdokumentation listet alle verfügbaren Optionen. Neben dieser lokalen Variante gibt es die Möglichkeit, die swagger.json per CLI in die Scalar Registry zu pushen. Damit wird die Dokumentation zentral gehostet und ist für alle Teammitglieder zugänglich, ohne dass der Server laufen muss.
Docs in die Scalar Registry pushen
Die Scalar Registry ist ein zentrales API-Dokumentationsportal unter scalar.com. Öffentliche APIs sind kostenlos hostbar; für private Docs und Team-Features gibt es bezahlte Pläne (Details dazu im Überblick oben). Für den Push benötigst du einen Scalar-Account und einen API Key, den du unter Settings → API Keys auf scalar.com findest.
Lokal läuft der Push in drei Schritten: swagger.json aus der kompilierten DLL exportieren, die Scalar CLI installieren und den Push-Befehl ausführen:
# Scalar CLI global installieren
npm install -g @scalar/cli
# swagger.json aus dem .NET-Build exportieren
dotnet swagger tofile --output ./swagger.json ./bin/Release/net9.0/MyApi.dll v1
# In die Scalar Registry pushen
scalar publish \
--api-key "$SCALAR_API_KEY" \
--name "my-api" \
--version "v1" \
./swagger.json
Für den CI-Betrieb lässt sich dieser Schritt direkt nach dem Build einbinden. Ein GitHub Actions Job sieht so aus:
# .github/workflows/publish-docs.yml
name: Push API Docs to Scalar
on:
push:
branches: [main]
jobs:
publish-docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.x'
- name: Build
run: dotnet build --configuration Release
- name: Export swagger.json
run: dotnet swagger tofile --output ./swagger.json ./bin/Release/net9.0/MyApi.dll v1
- name: Install Scalar CLI
run: npm install -g @scalar/cli
- name: Publish to Scalar Registry
env:
SCALAR_API_KEY: ${{ secrets.SCALAR_API_KEY }}
run: |
scalar publish \
--api-key "$SCALAR_API_KEY" \
--name "my-api" \
--version "v1" \
./swagger.json
In Azure DevOps funktioniert dasselbe Muster mit einem Npm@1-Task und einem nachfolgenden script-Step. Den SCALAR_API_KEY speicherst du als Secret (GitHub Secrets bzw. Azure DevOps Variable Group mit Lock) und nie als Klartextvariable. Push-Regeln solltest du auf main oder Release-Branches beschränken, nicht auf jeden Feature-Branch-Commit.
OAuth2 konfigurieren
Wer seine API mit einer Authentifizierung absichert, kann Scalar so konfigurieren, dass die Authentifizierung direkt in der UI funktioniert. Ähnlich wie man es von Swagger UI kennt, werden die Security Schemes aus der OpenAPI-Spec erkannt und in Scalar als Auth-Optionen angeboten. Zusätzlich können hier noch weitere Optionen wie die Vorauswahl von Scopes oder die PKCE-Konfiguration für den Authorization Code Flow getroffen werden.
Voraussetzung ist ein korrekt definiertes Security Scheme in der Swashbuckle-Konfiguration. Für einen OAuth2 Authorization Code Flow mit Azure AD sieht das so aus:
// Program.cs – OAuth2 Security Scheme für Swashbuckle
builder.Services.AddSwaggerGen(options =>
{
options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
{
Type = SecuritySchemeType.OAuth2,
Flows = new OpenApiOAuthFlows
{
AuthorizationCode = new OpenApiOAuthFlow
{
AuthorizationUrl = new Uri("https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize"),
TokenUrl = new Uri("https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token"),
Scopes = new Dictionary<string, string>
{
{ "api://my-api/.default", "Vollzugriff auf die API" }
}
}
}
});
options.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" }
},
["api://my-api/.default"]
}
});
});
Scalar wird dann so konfiguriert, dass es die Client-ID und die Scopes vorausfüllt. Optionen wie Theme, Titel und weitere Auth-Flows finden sich in der Scalar Konfigurationsdokumentation. Das OAuth2-Setup sieht so aus:
// Program.cs – Scalar OAuth2-Konfiguration
app.MapScalarApiReference(options =>
{
options.WithOpenApiRoutePattern("/swagger/v1/swagger.json");
options
.AddPreferredSecuritySchemes("OAuth2")
.AddAuthorizationCodeFlow("OAuth2", flow =>
{
flow.ClientId = "scalar-demo-client";
flow.Pkce = Pkce.Sha256;
flow.SelectedScopes = ["read", "write", "admin"];
});
});
Damit der Authorization Code Flow funktioniert, muss die Redirect URI http://localhost:PORT/scalar in der Client Registration eingetragen sein. Nach dem Klick auf Authenticate leitet Scalar zum Identity Provider weiter, speichert den Token im Browser-Session-Storage und fügt ihn bei allen nachfolgenden Requests automatisch als Bearer-Token ein. Scalar unterstützt daneben auch API Key und HTTP Bearer direkt über die Konfiguration.
API-Versionen verwalten
In größeren .NET-Projekten laufen v1 und v2 einer API oft parallel. Mit Asp.Versioning und Swashbuckle entstehen separate Dokumente unter /swagger/v1/swagger.json und /swagger/v2/swagger.json. Scalar lässt sich für beide Versionen separat registrieren:
// Program.cs – Multi-Version Setup mit Swashbuckle und Scalar
builder.Services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
options.SwaggerDoc("v2", new OpenApiInfo { Title = "My API", Version = "v2" });
});
// Separate Scalar-Endpunkte für jede Version
app.MapScalarApiReference("/scalar/v1", options =>
{
options.WithTitle("My API v1");
options
.AddDocument("v1", "/swagger/v1/swagger.json")
.AddDocument("v2", "/swagger/v2/swagger.json");
});
In der Registry pushst du jede Version separat mit dem --version-Flag:
scalar publish --api-key "$SCALAR_API_KEY" --name "my-api" --version "v1" ./swagger-v1.json
scalar publish --api-key "$SCALAR_API_KEY" --name "my-api" --version "v2" ./swagger-v2.json
Konsistente Namen nach dem Schema {service}-v{major}, also z. B. orders-v1 und orders-v2, verhindern Registry-Wildwuchs, sobald die Anzahl der Microservices wächst. Verlinkung in der README oder im Developer Portal auf die versionierten Scalar-URLs macht den Wechsel zwischen Versionen für API-Konsumenten einfach.
Aspire und weitere Integrationen
Wer mehrere Services hat und diese mit .NET Aspire orchestriert, profitiert besonders von der Scalar-Integration.
Scalar unterstützt .NET Aspire. AddScalarApiReference() im Aspire App Host registriert OpenAPI-Endpunkte und das Aspire Dashboard verlinkt auf die Scalar UI der einzelnen Services.
Die Scalar .NET Aspire Integration beschreibt das Setup im Detail.
Das Ergebnis ist eine Discovery-Ansicht aller Services mit einem konsollidierten API-Reference-Portal, das die Dokumentation aller Services zentralisiert und die Navigation zwischen ihnen erleichtert.
var builder = DistributedApplication.CreateBuilder(args);
// Add your services
var userService = builder.AddNpmApp("user-service", "../MyUserService");
var bookService = builder.AddProject<Projects.BookService>("book-service");
// Add Scalar API Reference
var scalar = builder.AddScalarApiReference();
// Register services with the API Reference
scalar
.WithApiReference(userService)
.WithApiReference(bookService);
Darüber hinaus gibt es eine Scalar VS Code Extension, die API-Docs direkt im Editor anzeigt, sowie ein IntelliJ Plugin. Für statisches Hosting exportiert scalar export eine vollständige HTML-Datei, die auf Azure Static Web Apps, GitHub Pages oder Netlify gehostet werden kann.
Fallstricke und Best Practices
Ein Punkt, der in der Praxis gerne übersehen wird, ist CORS. Wenn Scalar vom Browser aus eine remote gehostete swagger.json nachladen soll, benötigt der .NET-Server den passenden CORS-Header. In der Entwicklung ist das meist kein Problem; in der Produktion empfiehlt sich entweder eine explizite Konfiguration oder der Push-Ansatz, bei dem Scalar die bereits hochgeladene Datei aus der Registry liest:
// CORS für Scalar Registry konfigurieren (nur wenn Remote-Load genutzt wird)
builder.Services.AddCors(options =>
{
options.AddPolicy("ScalarHosting", policy =>
policy.WithOrigins("https://scalar.com")
.AllowAnyHeader()
.AllowAnyMethod());
});
app.UseCors("ScalarHosting");
Ein weiterer Punkt ist die Sichtbarkeit von /swagger und /scalar in der Produktion. Der OpenAPI-Spec enthält die vollständige API-Struktur und ist ein nützlicher Ausgangspunkt für Reconnaissance-Angriffe. Bei internen APIs solltest du die Endpunkte auf interne Netze oder hinter eine Auth-Wall beschränken:
// Scalar und Swagger nur in Entwicklung und Staging exponieren
if (app.Environment.IsDevelopment() || app.Environment.IsStaging())
{
app.UseSwagger();
app.MapScalarApiReference();
}
Bei der Migration von Swagger UI gibt es einige Stolpersteine: Custom CSS-Injektionen und benutzerdefinierte Auth-Interceptoren werden von Scalar nicht übernommen. Die Scalar Theme-API bietet eigene Anpassungsmöglichkeiten, aber der Aufwand muss eingeplant werden. Vendor Extensions (x--Felder) rendern in Scalar teils anders als in Swagger UI, daher lohnt sich ein manueller Durchlauf der eigenen Specs vor der Umstellung.
Um Breaking Changes vor dem Push zur Registry zu erkennen, bietet sich oasdiff in der CI-Pipeline an. Der Push erfolgt erst nach erfolgreichem Diff-Check, sodass Konsumenten keine unangekündigten Breaking Changes erhalten. Für sehr große OpenAPI-Specs über 1 MB empfiehlt sich das Aufteilen in kleinere Dateien pro Kategorie oder Bereich, da die Scalar UI sonst spürbar langsamer wird.
Scalar in einem Tag
Scalar ist kein großes Migrationsprojekt. Das NuGet-Paket ist in wenigen Minuten eingebunden, und der erste lokale UI-Test zeigt sofort, was sich gegenüber Swagger UI ändert. Wer die Registry nutzen will, für den ist der Registry-Push ein einzelner CLI-Befehl, der sich leicht in jede bestehende CI-Pipeline integrieren lässt.
Der sinnvolle Einstiegspunkt ist pragmatisch: Nimm dein nächstes .NET-Projekt, füge Scalar.AspNetCore hinzu und vergleiche drei kritische Endpunkte direkt im Scalar-UI, ohne Postman, ohne extra Setup. Danach entscheidest du, ob sich der vollständige Umstieg lohnt.
Wie sind deine Erfahrungen mit Scalar oder anderen API-Dokumentationstools? Schau gerne bei uns auf LinkedIn vorbei und diskutiere mit.