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

> Master ASP.NET Core 7+ output caching configuration with this guide. Learn in-memory and Redis storage setup to boost your application performance.

- Repository: [.NET Platform/aspnetcore](https://github.com/dotnet/aspnetcore)
- Tags: how-to-guide
- Published: 2026-06-20

---

**ASP.NET Core 7+ output caching configuration requires calling `AddOutputCache()` in [`Program.cs`](https://github.com/dotnet/aspnetcore/blob/main/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`](https://github.com/dotnet/aspnetcore/blob/main/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:

- **`OutputCacheMiddleware`** – The core pipeline component that intercepts requests, generates cache keys, and serves stored responses from [`src/Middleware/OutputCaching/src/OutputCacheMiddleware.cs`](https://github.com/dotnet/aspnetcore/blob/main/src/Middleware/OutputCaching/src/OutputCacheMiddleware.cs).
- **`OutputCacheOptions`** – Global configuration for size limits, default expiration, and vary-by rules located in [`src/Middleware/OutputCaching/src/OutputCacheOptions.cs`](https://github.com/dotnet/aspnetcore/blob/main/src/Middleware/OutputCaching/src/OutputCacheOptions.cs).
- **`OutputCacheAttribute`** – Declarative metadata for per-endpoint cache policies including duration and vary-by parameters in [`src/Middleware/OutputCaching/src/OutputCacheAttribute.cs`](https://github.com/dotnet/aspnetcore/blob/main/src/Middleware/OutputCaching/src/OutputCacheAttribute.cs).
- **`IOutputCacheFeature`** – Runtime API for programmatic cache control and tagging accessed via `HttpContext.Features` in [`src/Middleware/OutputCaching/src/IOutputCacheFeature.cs`](https://github.com/dotnet/aspnetcore/blob/main/src/Middleware/OutputCaching/src/IOutputCacheFeature.cs).
- **`IOutputCachePolicyProvider`** – Service for resolving named cache policies defined in [`src/Middleware/OutputCaching/src/IOutputCachePolicyProvider.cs`](https://github.com/dotnet/aspnetcore/blob/main/src/Middleware/OutputCaching/src/IOutputCachePolicyProvider.cs).

## How the Output Caching Pipeline Works

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

1. **Registration Phase** – `AddOutputCache()` registers the in-memory store, policy provider, and supporting services in the dependency injection container.
2. **Pipeline Insertion** – `UseOutputCache()` 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:

```csharp
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`](https://github.com/dotnet/aspnetcore/blob/main/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:

```csharp
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`](https://github.com/dotnet/aspnetcore/blob/main/src/Middleware/Microsoft.AspNetCore.OutputCaching.StackExchangeRedis/src/StackExchangeRedisCacheServiceCollectionExtensions.cs) and utilizes `RedisOutputCacheOptions` from [`src/Middleware/Microsoft.AspNetCore.OutputCaching.StackExchangeRedis/src/RedisOutputCacheOptions.cs`](https://github.com/dotnet/aspnetcore/blob/main/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:

```csharp
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`](https://github.com/dotnet/aspnetcore/blob/main/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:

```csharp
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:

```csharp
await cacheService.EvictByTagAsync("products");

```

## Advanced Configuration Patterns

### Custom Cache Policies

Define reusable named policies by configuring `OutputCacheOptions`:

```csharp
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`](https://github.com/dotnet/aspnetcore/blob/main/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`](https://github.com/dotnet/aspnetcore/blob/main/OutputCacheMiddleware.cs), [`OutputCacheOptions.cs`](https://github.com/dotnet/aspnetcore/blob/main/OutputCacheOptions.cs), and [`RedisOutputCacheOptions.cs`](https://github.com/dotnet/aspnetcore/blob/main/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.