Output Caching in .NET 10 Web API

Introduction

Modern web APIs handle many requests, sometimes thousands or millions. Running the same work every time (like database calls, data changes, and checks) can be slow and costly.

Output caching helps solve this. It is a powerful feature in .NET that can greatly improve performance.

The sample code can be downloaded from GitHub

What is Output Caching?

Output caching saves the full HTTP response (status code, headers, and body) so the same request can be returned directly from cache.

Output caching was added as middleware in .NET 7 and improved in later versions. It replaces older methods like response caching and gives you more control on the server side.

Simple Flow

  • Client sends request → /api/products

  • Server processes it → gets data from database

  • Response is saved in cache

Next time the same request comes:

  • Response is returned from cache

  • Controller logic is skipped

How to Enable Output Caching in .NET 10.0?

Register Service

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOutputCache();

var app = builder.Build();
app.UseOutputCache();

Apply to Endpoints

app.MapGet("/weatherforecast", () =>
{
    Console.WriteLine("Generating weather forecast...before caching");
    var forecast = Enumerable.Range(1, 5).Select(index =>
        new WeatherForecast
        (
            DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            Random.Shared.Next(-20, 55),
            summaries[Random.Shared.Next(summaries.Length)]
        ))
        .ToArray();
    return forecast;
})
.WithName("GetWeatherForecast")
.CacheOutput(policy => policy.Expire(TimeSpan.FromSeconds(60))); // Cache the response for 60 seconds

Now repeated requests will be served from cache.

Controlling Cache Duration

.CacheOutput(policy =>
{
    policy.Expire(TimeSpan.FromSeconds(60));
});
  • The response is cached for 60 seconds.

  • After 60 seconds, a new response is created.

Varying Cache (Very Important)

Not every request is the same. You need to define what makes each request different.

Vary by Route

.CacheOutput(policy =>
{
    policy.SetVaryByRouteValue("id");
});
  • /products/1 and /products/2 will be stored in separate cache entries

Vary by Query Parameters

.CacheOutput(policy =>
{
    policy.SetVaryByQuery("page", "pageSize");
});
  • Helpful for pagination and filtering

Vary by Headers (Advanced)

.CacheOutput(policy =>
{
    policy.SetVaryByHeader("Authorization");
});
  • Creates separate cache for each user token (use with caution!)

Common Mistakes

  • Caching Sensitive Data – Avoid caching when dealing with user-specific private info and financial data

  • Not Using Vary – Leads to wrong data returned to users

  • Over-Caching – Do not cache real-time data and frequently changing values

  • Cache Explosion – SetVaryByHeader("Authorization") creates cache per user, which internally leads to memory issues

When to Use Output Caching

  • Read-heavy APIs

  • Public endpoints

  • High-traffic systems

  • Microservices

When NOT to Use It

  • Real-time systems

  • Payment APIs

  • Highly dynamic data

  • Sensitive user data

Example: Output Caching with WeatherForecast API

A simple and common use case for output caching is a Weather Forecast API, where data does not change every second and can be safely reused for a short time.

Endpoint Without Caching

app.MapGet("/weatherforecast/nocache", () =>
{
    Console.WriteLine("Generating weather forecast...no caching");
    var forecast = Enumerable.Range(1, 5).Select(index =>
        new WeatherForecast
        (
            DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            Random.Shared.Next(-20, 55),
            summaries[Random.Shared.Next(summaries.Length)]
        ))
        .ToArray();
    return forecast;
})
.WithName("GetWeatherForecastNoCache");

Every request:

  • Executes logic again

  • Hits DB/external service if there are any

  • Increases latency under load

With Output Caching

app.MapGet("/weatherforecast", () =>
{
    Console.WriteLine("Generating weather forecast...before caching");
    var forecast = Enumerable.Range(1, 5).Select(index =>
        new WeatherForecast
        (
            DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            Random.Shared.Next(-20, 55),
            summaries[Random.Shared.Next(summaries.Length)]
        ))
        .ToArray();
    return forecast;
})
.WithName("GetWeatherForecast")
.CacheOutput(policy => policy.Expire(TimeSpan.FromSeconds(60))); // Cache the response for 60 seconds

What Happens Now

  • First request → executes logic + stores response in cache

  • Next requests (within 60 seconds) → served from cache instantly

  • After 60 seconds → cache expires and fresh data is generated

Conclusion

Output caching is a simple but very effective way to improve performance in modern Web APIs. It saves full HTTP responses and reuses them for repeated requests, so the server doesn’t need to run the same logic again. This helps reduce server load and makes responses faster.

For example, in a WeatherForecast API, data changes only sometimes, not every request. In such cases, output caching works very well. With a short expiry time, users still get fast responses while the data stays reasonably up to date.

But caching must be used carefully. You need to choose the right APIs, set proper rules for when cached data should differ, and avoid caching sensitive or frequently changing data.

In short, when used correctly, output caching makes a Web API faster, more efficient, and ready to handle high traffic.

Happy Coding!