logo

{ TECH BLOG }

Building Scalable APIs with .NET 9 and C# 13

20-Mar-2026By Mamina Suman


.NET 9 — What's New for API Development

.NET 9 brings significant improvements for API developers: native AOT compilation for minimal APIs, improved OpenAPI support, enhanced distributed caching, and better observability with built-in OpenTelemetry integration. Combined with C# 13's new language features, building high-performance APIs has never been more streamlined.

Minimal APIs with Native AOT


var builder = WebApplication.CreateSlimBuilder(args);
builder.Services.AddSingleton<IProductService, ProductService>();

var app = builder.Build();

app.MapGet("/api/products", async (IProductService service) =>
    Results.Ok(await service.GetAllAsync()));

app.MapGet("/api/products/{id}", async (int id, IProductService service) =>
    await service.GetByIdAsync(id) is Product product
        ? Results.Ok(product)
        : Results.NotFound());

app.MapPost("/api/products", async (CreateProductDto dto, IProductService service) =>
{
    var product = await service.CreateAsync(dto);
    return Results.Created($"/api/products/{product.Id}", product);
});

app.Run();

With native AOT, startup times drop from seconds to milliseconds, and memory usage is reduced by up to 80%. This is game-changing for serverless deployments where cold starts matter.

API Architecture Patterns

  • CQRS — Separate read and write models for optimal performance at scale
  • Vertical Slice Architecture — Organize code by feature, not by layer. Each endpoint is a self-contained slice.
  • Result Pattern — Replace exceptions with explicit Result types for cleaner error handling
  • API Versioning — Use URL-based or header-based versioning with Asp.Versioning
  • Rate Limiting — Built-in rate limiting middleware in .NET 9 with sliding window and token bucket algorithms

Observability & Monitoring

.NET 9 has first-class OpenTelemetry support. Configure traces, metrics, and logs with a few lines of code. Combined with tools like Grafana, Jaeger, and Prometheus, you get full observability across your API ecosystem. Use health checks, structured logging with Serilog, and distributed tracing to diagnose issues in production quickly.

Production-Ready API Configuration

Here's a complete production setup with rate limiting, caching, and OpenTelemetry:


var builder = WebApplication.CreateBuilder(args);

// Add services
builder.Services.AddOutputCache(options =>
{
    options.AddBasePolicy(builder => builder.Expire(TimeSpan.FromMinutes(5)));
});

builder.Services.AddRateLimiter(options =>
{
    options.AddFixedWindowLimiter("api", opt =>
    {
        opt.Window = TimeSpan.FromMinutes(1);
        opt.PermitLimit = 100;
    });
});

// OpenTelemetry
builder.Services.AddOpenTelemetry()
    .WithTracing(tracing => tracing
        .AddAspNetCoreInstrumentation()
        .AddHttpClientInstrumentation()
        .AddOtlpExporter())
    .WithMetrics(metrics => metrics
        .AddAspNetCoreInstrumentation()
        .AddOtlpExporter());

var app = builder.Build();

app.UseRateLimiter();
app.UseOutputCache();

app.MapGet("/api/products", async (IProductService service) =>
{
    var products = await service.GetAllAsync();
    return Results.Ok(products);
})
.CacheOutput()
.RequireRateLimiting("api");

app.Run();

Performance Optimization Tips

From building APIs handling 10M+ requests/day, here are key optimizations:

  • Use Output Caching — .NET 9's output cache is 3x faster than response caching. Cache entire HTTP responses at the edge.
  • Async All The Way — Never block async code with .Result or .Wait(). Use async/await consistently.
  • Connection Pooling — Use HttpClientFactory and database connection pooling. Never create new clients per request.
  • Pagination — Always paginate large result sets. Use keyset pagination for better performance than offset-based.
  • Compression — Enable response compression for JSON payloads > 1KB (Brotli for static, Gzip for dynamic).
  • Native AOT — For serverless/container deployments, native AOT reduces cold start from 2s to 50ms.

We reduced P99 latency from 800ms to 120ms by implementing these patterns. The biggest win was switching from offset pagination to keyset pagination for our largest tables.

If you have any questions or suggestions for this blog, please leave a comment below. I will get back to you ASAP. For contacting me please use the site's Contact form or you can directly mail me [email protected].

If you have any project or technical challenge on your mind, please be in touch with me here.
For my recent work please visit the portfolio section.