ASP.NET Core 7+ Output Caching Configuration: Complete Guide to In-Memory and Redis Storage

ASP.NET Core 7+ output caching configuration requires calling AddOutputCache() in Program.cs, inserting UseOutputCache() into the middleware pipeline, and applying the [OutputCache] attribute or IOutputCacheFeature to endpoints, with optional Redis backing via AddStackExchangeRedisOutputCache.

ASP.NET Core 7 introduces a built-in output caching middleware that caches complete HTTP responses—including status codes, headers, and response bodies—to eliminate redundant MVC pipeline executions on repeat requests. According to the dotnet/aspnetcore source code, this middleware is implemented in OutputCacheMiddleware.cs and configured through OutputCacheOptions, supporting both in-memory storage and distributed Redis backends. Proper configuration of ASP.NET Core 7+ output caching enables dramatic latency reductions while maintaining flexible cache invalidation and vary-by rules.

Core Components of the Output Caching System

The output caching middleware consists of several interconnected services defined in the src/Middleware/OutputCaching/src/ directory:

How the Output Caching Pipeline Works

The middleware follows a specific execution flow defined in the dotnet/aspnetcore implementation:

  1. Registration PhaseAddOutputCache() registers the in-memory store, policy provider, and supporting services in the dependency injection container.
  2. Pipeline InsertionUseOutputCache() must appear early in the middleware pipeline, typically before authentication and authorization components if cached responses should bypass those checks.
  3. Cache Key Generation – For incoming requests, the middleware constructs a cache key from the request path, query string values (based on VaryByQueryKeys), and specified headers.
  4. Lookup and Short-Circuit – If a matching entry exists, the middleware writes the stored status code, headers, and body directly to the response and terminates the pipeline.
  5. Storage and Tagging – For cache misses, the request proceeds to the endpoint. After response generation, the middleware stores the response if cacheable (status 200-299, no Cache-Control: no-store, non-streaming), applying tags via IOutputCacheFeature for later invalidation.

Configuring Output Caching in Program.cs

Registering the Middleware

Add the output caching services to your application builder and insert the middleware into the pipeline:

var builder = WebApplication.CreateBuilder(args);

// Register output caching with in-memory storage
builder.Services.AddOutputCache(options =>
{
    options.MaximumBodySize = 100 * 1024 * 1024; // 100 MB limit
    options.MaximumResponseCount = 1000;         // LRU eviction threshold
    options.DefaultExpirationTimeSpan = TimeSpan.FromSeconds(30);
});

var app = builder.Build();

// Insert before components you want to skip on cache hits
app.UseOutputCache();

app.MapControllers(); // or MapGet, MapRazorPages, etc.
app.Run();

Place UseOutputCache() before UseAuthentication() or UseAuthorization() only if you want cached responses to bypass authentication checks. For authenticated endpoints, place authentication middleware before the cache middleware.

Global Configuration Options

The OutputCacheOptions class in src/Middleware/OutputCaching/src/OutputCacheOptions.cs exposes these key properties:

  • MaximumBodySize – Maximum response body size in bytes that can be cached (default 64 MB).
  • DefaultExpirationTimeSpan – Default cache duration when not specified per-endpoint.
  • VaryByHeaderNames – Global headers to include in cache key generation.
  • Policies – Collection of named policies accessible via IOutputCachePolicyProvider.

Configuring Redis Distributed Output Caching

For multi-instance deployments, replace the in-memory store with Redis using the Microsoft.AspNetCore.OutputCaching.StackExchangeRedis package:

builder.Services.AddStackExchangeRedisOutputCache(redisOptions =>
{
    redisOptions.Configuration = "localhost:6379";
    redisOptions.InstanceName = "AspNetCoreCache:";
});

This extension method is defined in src/Middleware/Microsoft.AspNetCore.OutputCaching.StackExchangeRedis/src/StackExchangeRedisCacheServiceCollectionExtensions.cs and utilizes RedisOutputCacheOptions from src/Middleware/Microsoft.AspNetCore.OutputCaching.StackExchangeRedis/src/RedisOutputCacheOptions.cs for connection configuration. When Redis is configured, IOutputCacheService methods work transparently across all instances, with entries serialized using MessagePack.

Endpoint-Level Caching Configuration

Using the OutputCache Attribute

Apply the [OutputCache] attribute to controllers, actions, or minimal API endpoints to override global settings:

using Microsoft.AspNetCore.OutputCaching;

[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    // Cache for 60 seconds, vary by "category" query string
    [HttpGet]
    [OutputCache(Duration = 60, VaryByQueryKeys = new[] { "category" }, Tags = new[] { "products" })]
    public async Task<IActionResult> Get([FromQuery] string category)
    {
        return Ok(await _repository.GetByCategoryAsync(category));
    }
}

The OutputCacheAttribute in src/Middleware/OutputCaching/src/OutputCacheAttribute.cs supports:

  • Duration – Cache lifetime in seconds.
  • VaryByQueryKeys – Array of query parameter names to include in the cache key.
  • VaryByHeaderNames – Header names that affect cache key uniqueness (e.g., Accept-Language).
  • Tags – String tags for bulk invalidation via IOutputCacheService.EvictByTagAsync().
  • NoStore – Boolean to disable caching for specific endpoints.

Programmatic Cache Control

For dynamic cache metadata, use IOutputCacheFeature inside your endpoint logic:

app.MapGet("/products/{id}", async (int id, HttpContext context, IOutputCacheService cacheService) =>
{
    var feature = context.Features.Get<IOutputCacheFeature>();
    
    // Add runtime tags for cache invalidation
    feature?.AddTag("products");
    feature?.AddTag($"product-{id}");
    
    return Results.Ok(await GetProductAsync(id));
});

Invalidate entries by tag programmatically:

await cacheService.EvictByTagAsync("products");

Advanced Configuration Patterns

Custom Cache Policies

Define reusable named policies by configuring OutputCacheOptions:

builder.Services.AddOutputCache(options =>
{
    options.AddPolicy("LongCache", policy => 
    {
        policy.Expire(TimeSpan.FromMinutes(5));
        policy.VaryByQuery("version");
    });
});

Apply policies by name: [OutputCache(PolicyName = "LongCache")].

Cache Size Management

The in-memory implementation enforces LRU (Least Recently Used) eviction when limits are exceeded. Control these boundaries via:

  • MaximumResponseCount – Total number of entries stored across all endpoints.
  • MaximumBodySize – Per-entry size limit to prevent memory exhaustion from large responses.

Summary

  • ASP.NET Core 7+ output caching caches complete HTTP responses in memory or Redis to bypass expensive endpoint execution.
  • Configuration requires AddOutputCache() for service registration and UseOutputCache() for pipeline insertion, with optional Redis setup via AddStackExchangeRedisOutputCache.
  • Per-endpoint control uses the [OutputCache] attribute from src/Middleware/OutputCaching/src/OutputCacheAttribute.cs for declarative settings or IOutputCacheFeature for runtime tagging.
  • Invalidation operates via tags using IOutputCacheService.EvictByTagAsync(), enabling targeted cache clearing across distributed instances.
  • Source files in dotnet/aspnetcore such as OutputCacheMiddleware.cs, OutputCacheOptions.cs, and RedisOutputCacheOptions.cs define the implementation details for customization and debugging.

Frequently Asked Questions

What is the difference between output caching and response caching in ASP.NET Core?

Output caching (ASP.NET Core 7+) stores the complete rendered response on the server and bypasses the entire request pipeline on cache hits, while response caching (via [ResponseCache] attribute) primarily sets HTTP headers to instruct clients and proxies to cache. Output caching is server-side and can cache responses for authenticated requests, whereas response caching depends on client cooperation.

How do I invalidate cached responses in ASP.NET Core 7+?

Use the IOutputCacheService interface and call EvictByTagAsync("tag-name") to remove all entries marked with that specific tag. You can also add tags programmatically via IOutputCacheFeature.AddTag() during request processing to enable granular invalidation groups.

Can I use output caching with authenticated endpoints?

Yes, but you must place UseOutputCache() after UseAuthentication() and UseAuthorization() in the middleware pipeline. This ensures the cache key includes the authenticated user context (via VaryByHeaderNames or custom key providers) and prevents serving cached responses to unauthenticated users.

How do I configure output caching to store responses larger than 64 MB?

Set the MaximumBodySize property in OutputCacheOptions during service registration: options.MaximumBodySize = 100 * 1024 * 1024 for 100 MB. Be aware that extremely large cached responses consume significant memory or Redis bandwidth, so consider implementing custom IOutputCacheKeyProvider logic to segment large resources.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →