API Documentation with Scalar and OpenAPI in .NET

Good API documentation is the difference between developers adopting your API in minutes or abandoning it after an hour. ASP.NET Core has native support for generating OpenAPI documents from .NET 9 onwards, and Scalar provides a modern, polished UI to render them — replacing the ageing Swagger UI that has been the .NET default for years.

OpenAPI in .NET 9+

Starting with .NET 9, ASP.NET Core includes built-in OpenAPI document generation via Microsoft.AspNetCore.OpenApi. No Swashbuckle required.

Program.cs
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddOpenApi();

var app = builder.Build();

app.MapOpenApi(); // Serves the OpenAPI document at /openapi/v1.json

app.MapGet("/api/orders", () => new[] { new Order(1, "Acme Ltd", 199.99m) })
    .WithName("GetOrders")
    .WithSummary("Returns all orders")
    .WithDescription("Retrieves a list of all orders in the system.");

app.MapGet("/api/orders/{id:int}", (int id) =>
        id == 1 ? Results.Ok(new Order(1, "Acme Ltd", 199.99m)) : Results.NotFound())
    .WithName("GetOrderById")
    .WithSummary("Returns a single order")
    .Produces<Order>(200)
    .ProducesProblem(404);

app.Run();

record Order(int Id, string CustomerName, decimal Total);

The WithName, WithSummary, Produces, and ProducesProblem methods enrich the generated OpenAPI document with operation details, response schemas, and status codes.

Adding Scalar

Scalar is an open-source API documentation tool that renders OpenAPI documents as clean, interactive documentation. Install the Scalar.AspNetCore package:

Program.cs
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddOpenApi();

var app = builder.Build();

app.MapOpenApi();
app.MapScalarApiReference(); // Serves Scalar UI at /scalar/v1

app.MapGet("/api/orders", GetOrders);
app.MapPost("/api/orders", CreateOrder);

app.Run();

Navigate to /scalar/v1 and you get a modern documentation page with:

Customising Scalar

Scalar supports theming and configuration:

Example.cs
app.MapScalarApiReference(options =>
{
    options.Title = "Order Service API";
    options.Theme = ScalarTheme.DeepSpace;
    options.DefaultHttpClient = new(ScalarTarget.CSharp, ScalarClient.HttpClient);
    options.ShowSidebar = true;
});

The DefaultHttpClient option controls which language and client the code examples default to — useful when your audience is primarily .NET developers.

Enriching the OpenAPI Document

The built-in OpenAPI generation picks up type information automatically, but you should add metadata for a complete document.

Tags for Grouping

Example.cs
app.MapGet("/api/orders", GetOrders)
    .WithTags("Orders");

app.MapGet("/api/customers", GetCustomers)
    .WithTags("Customers");

XML Comments

Enable XML documentation in your project file and configure OpenAPI to include it:

config.xml
<PropertyGroup>
  <GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>

For controllers, XML comments on action methods flow into the OpenAPI document automatically. For minimal APIs, use WithDescription and WithSummary.

Document-Level Metadata

Configure the OpenAPI document info:

Example.cs
builder.Services.AddOpenApi(options =>
{
    options.AddDocumentTransformer((document, context, ct) =>
    {
        document.Info = new()
        {
            Title = "Order Service API",
            Version = "v1",
            Description = "API for managing customer orders.",
            Contact = new() { Name = "Platform Team", Email = "[email protected]" }
        };
        return Task.CompletedTask;
    });
});

Securing the Documentation

In production, you may want to restrict access to the documentation:

Example.cs
app.MapOpenApi()
    .RequireAuthorization("ApiDocumentationPolicy");

app.MapScalarApiReference()
    .RequireAuthorization("ApiDocumentationPolicy");

Or serve documentation only in development:

Example.cs
if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
    app.MapScalarApiReference();
}

Why Scalar Over Swagger UI

Swagger UI has served the .NET ecosystem well, but it shows its age. Scalar offers:

With .NET 9's built-in OpenAPI support and Scalar's rendering, you get professional API documentation with minimal setup and no dependency on Swashbuckle. There is no reason not to document your APIs well.