When your API serves the same data repeatedly, every request hits your database and business logic unnecessarily. Output Caching stores the complete HTTP response and serves it directly for subsequent requests, dramatically improving performance and reducing server load.
ASP.NET Core 7+ includes built-in Output Caching middleware that's more powerful and flexible than the older Response Caching.
| Feature | Output Caching | Response Caching |
| Cache location | Server-side | Client/proxy (HTTP headers) |
| Control | Full programmatic control | Depends on client behavior |
| Invalidation | Tag-based, programmatic | Time-based only |
| Cache storage | Memory, Redis, custom | N/A (client-side) |
// Program.csvar builder = WebApplication.CreateBuilder(args);builder.Services.AddOutputCache(options =>{// Default policy - cache for 60 secondsoptions.AddBasePolicy(builder => builder.Expire(TimeSpan.FromSeconds(60)));// Named policy for specific endpointsoptions.AddPolicy("CacheProducts", builder =>builder.Expire(TimeSpan.FromMinutes(10)).Tag("products"));});var app = builder.Build();app.UseOutputCache();
✅ Figure: Good example - Configure output caching with default and named policies
// Without caching - hits database every timeapp.MapGet("/api/products", async (ProductDbContext db) =>{return await db.Products.ToListAsync();});
❌ Figure: Bad example - No caching means unnecessary database hits for unchanged data
// With output caching - serves cached responseapp.MapGet("/api/products", async (ProductDbContext db) =>{return await db.Products.ToListAsync();}).CacheOutput("CacheProducts");// Or inline policyapp.MapGet("/api/categories", async (ProductDbContext db) =>{return await db.Categories.ToListAsync();}).CacheOutput(policy => policy.Expire(TimeSpan.FromMinutes(5)));
✅ Figure: Good example - Cache responses to reduce database load
The real power of Output Caching is tag-based invalidation - when data changes, invalidate only the relevant cached responses.
app.MapPost("/api/products", async (Product product,ProductDbContext db,IOutputCacheStore cache) =>{db.Products.Add(product);await db.SaveChangesAsync();// Invalidate all responses tagged with "products"await cache.EvictByTagAsync("products", default);return Results.Created($"/api/products/{product.Id}", product);});
✅ Figure: Good example - Invalidate cache when data changes using tags
Use Output Caching when:
Don't use Output Caching when:
For multi-server deployments, use Redis as the cache store:
builder.Services.AddStackExchangeRedisOutputCache(options =>{options.Configuration = builder.Configuration.GetConnectionString("Redis");options.InstanceName = "MyApp:";});
✅ Figure: Good example - Use Redis for output caching in distributed environments