When an ASP.NET Core application receives many requests for the same data, it may repeat the same work again and again. It might run the same database query, build the same response, or call the same service for every request.
Caching can reduce this repeated work and help an application respond faster. However, ASP.NET Core offers different caching options, and choosing the wrong one can lead to unnecessary requests or, in some cases, users receiving data they should not see.
Two options worth understanding are Output Caching and Response Caching. Both can reduce the work involved in serving HTTP responses, but they operate differently.
In this article, we will compare these approaches, learn how to configure them in ASP.NET Core, and understand when each one makes sense for a real application.
What Is Output Caching in ASP.NET Core?
Output Caching stores the result of an endpoint on the server. When another request matches the caching policy, ASP.NET Core can return the stored response instead of running the endpoint again.
For example, imagine an API that returns a list of product categories. The list changes only occasionally, but the API receives requests throughout the day.
Without caching, the application might query the database for every request. With Output Caching, the server can reuse the response for a configured period.
Output Caching is built into modern ASP.NET Core applications through the Microsoft.AspNetCore.OutputCaching middleware and services.
Configure Output Caching
Start by registering the output cache service and adding the middleware in Program.cs.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddOutputCache(options =>
{
options.AddBasePolicy(policy =>
policy.Expire(TimeSpan.FromSeconds(60)));
});
var app = builder.Build();
app.UseRouting();
app.UseOutputCache();
app.MapControllers();
app.Run();
This example adds a base policy that allows eligible endpoints to cache responses for 60 seconds.
The middleware order matters. Output Caching should run after routing so it can use endpoint metadata. Authentication and authorization must also be configured correctly for applications that protect endpoints.
A global policy does not mean every response will automatically be cached. Endpoint eligibility and other caching rules still apply.
Enable Caching for an Endpoint
You can apply an output caching policy to a particular endpoint using the OutputCache attribute.
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OutputCaching;
using Microsoft.EntityFrameworkCore;
[ApiController]
[Route("api/categories")]
public class CategoriesController : ControllerBase
{
private readonly AppDbContext _context;
public CategoriesController(AppDbContext context)
{
_context = context;
}
[HttpGet]
[OutputCache(Duration = 60)]
public async Task<IActionResult> GetCategories()
{
var categories = await _context.Categories
.AsNoTracking()
.Select(c => new
{
c.Id,
c.Name
})
.ToListAsync();
return Ok(categories);
}
}
The first eligible request runs the database query and produces the response. Matching requests can reuse the cached result until it expires.
This example is suitable only when the category list can safely be shared among callers. If the response depends on the user's identity, permissions, or private data, the caching policy must account for those differences or disable shared caching.
What Is Response Caching in ASP.NET Core?
Response Caching follows HTTP caching rules. It uses response headers and request headers to determine whether a response can be cached and whether a cached response can be reused.
Unlike Output Caching, Response Caching does not simply provide a server-side cache for every eligible endpoint. It is designed to work with HTTP clients and intermediary caches that follow the caching rules.
For example, a browser or an eligible proxy may cache a public response when the server sends appropriate cache headers.
Configure Response Caching
Register the service and middleware:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddResponseCaching();
var app = builder.Build();
app.UseRouting();
app.UseResponseCaching();
app.MapControllers();
app.Run();
Now you can set cache-related headers on an endpoint.
[HttpGet("public-info")]
public IActionResult GetPublicInfo()
{
Response.Headers.CacheControl =
"public,max-age=60";
return Ok(new
{
Message = "This is public information."
});
}
The Cache-Control header tells compliant caches that the response can be stored and reused for up to 60 seconds, subject to the HTTP caching rules.
This endpoint should return information that is genuinely safe to share. Do not use public caching for responses containing private account information or data that varies by user permissions.
Also, setting a header does not guarantee that every browser or proxy will cache the response. The request, response, and intermediary configuration all affect caching behavior.
Output Caching vs. Response Caching
Although their names sound similar, these features solve different problems.
| Feature |
Output Caching |
Response Caching |
| Main purpose |
Reuse endpoint responses on the server |
Follow HTTP response caching rules |
| Main configuration |
Server-side caching policies |
HTTP caching headers and middleware |
| Server-side response reuse |
Yes, for eligible endpoints |
Not the primary purpose of the middleware |
| Browser or proxy caching |
Not its main focus |
Designed to support it |
| Policy control |
Endpoint policies and server-side rules |
HTTP headers and request directives |
| Best use case |
Repeated requests for stable endpoint results |
Public responses that clients or intermediaries can cache |
| User-specific data |
Requires careful policy design |
Must follow HTTP privacy and caching rules |
For many server-rendered pages and API endpoints, Output Caching is the more direct option when the goal is to avoid repeating endpoint work on the server.
Response Caching is useful when you want clients and compliant intermediaries to make caching decisions according to HTTP rules.
You can use both in the same application, but you should understand how their policies interact rather than enabling both everywhere.
When Should You Use Output Caching?
Output Caching is a good choice when:
- An endpoint returns the same result for many requests.
- The underlying data changes infrequently.
- Repeating database queries or response generation is unnecessary.
- You want to control caching through ASP.NET Core policies.
For example, product categories, public configuration data, and frequently requested public catalog pages may benefit from Output Caching.
You can also define named policies when different endpoints need different expiration times.
builder.Services.AddOutputCache(options =>
{
options.AddPolicy("ShortCache", policy =>
policy.Expire(TimeSpan.FromSeconds(30)));
options.AddPolicy("LongCache", policy =>
policy.Expire(TimeSpan.FromMinutes(5)));
});
Apply a named policy to an endpoint:
[HttpGet("catalog")]
[OutputCache(PolicyName = "LongCache")]
public IActionResult GetCatalog()
{
return Ok(new
{
Message = "Public catalog data"
});
}
This keeps caching decisions explicit and easier to maintain.
When Should You Use Response Caching?
Response Caching is a better fit when you want HTTP clients or intermediary caches to reuse eligible responses.
Consider a public API that returns static reference information, such as a list of supported regions. The server can send a suitable Cache-Control header and let compliant caches decide whether to reuse the response.
Response Caching can also work with validators such as ETags and Last-Modified to support conditional requests. When the representation has not changed, the server may return 304 Not Modified instead of sending the full response again.
However, response caching is not a substitute for server-side caching when your primary goal is to avoid database work on every request.
Common Caching Mistakes
Caching User-Specific Responses
Suppose an endpoint returns an account balance. If the cache does not distinguish between users, one user could receive another user's data.
Do not cache sensitive responses in a shared cache. Use appropriate authorization checks and avoid output caching for endpoints whose responses depend on user identity unless the cache policy explicitly and safely handles that variation.
Choosing an Expiration Time Without Considering Data Changes
A long expiration time can leave users with outdated information. A very short expiration time may provide little benefit.
Choose expiration based on how frequently the underlying data changes and how much staleness the application can tolerate.
Assuming Output Caching Works Across All Servers Automatically
The default output cache store is in-memory. In a multi-instance deployment, each instance can have its own cache, which means entries may differ or expire independently.
For distributed deployments, consider a shared cache store where supported and appropriate. You may also need an invalidation strategy when data changes.
Ignoring Cache Invalidation
A cached response may remain available until its policy expires or the cache entry is evicted or invalidated.
For data that changes frequently, use suitable expiration policies, tags, or other invalidation mechanisms instead of assuming every update automatically clears every related cache entry.
Caching Responses Containing Sensitive Headers
Be careful when caching responses that contain user-specific cookies, authorization-dependent data, or sensitive headers. Review the complete response and caching policy, not just the response body.
Best Practices for Production Applications
- Cache stable data first. Start with endpoints that return the same information to many callers.
- Keep private responses out of shared caches. Review authorization and user-specific behavior before enabling caching.
- Set realistic expiration times. Match cache lifetime to the rate at which the underlying data changes.
- Measure before and after. Monitor endpoint latency, database load, cache hit rates, and error rates to determine whether caching helps.
- Plan cache invalidation. Decide what happens when a product, category, or other cached record changes.
- Review multi-instance deployments. Understand whether the cache is local to each server or shared across instances.
- Test HTTP headers. Verify
Cache-Control, ETag behavior, and other relevant headers using actual requests.
- Avoid caching every endpoint. Authentication, personalized dashboards, and frequently changing transactional data often need different treatment.
- Use HTTPS and proper authorization. Caching does not replace access control.
- Document caching policies. Developers should know which endpoints may return stale data and for how long.
Advantages and Disadvantages
Output Caching
Advantages
- Reduces repeated endpoint execution for eligible requests.
- Can reduce repeated database queries and response-generation work.
- Provides server-side policies that can be configured per endpoint.
- Supports expiration and cache invalidation strategies.
Disadvantages
- Requires careful handling of user-specific responses.
- Can serve stale data until entries expire or are invalidated.
- In-memory entries are not automatically shared between application instances.
- Adds complexity when response variations and invalidation rules become extensive.
Response Caching
Advantages
- Uses standard HTTP caching behavior.
- Can reduce repeated response transfers when clients or intermediaries reuse cached data.
- Supports conditional requests and cache validators.
- Works well for suitable public responses.
Disadvantages
- Depends on HTTP caching rules and client or intermediary behavior.
- Does not primarily provide server-side endpoint-result caching.
- Requires correct cache headers and careful treatment of sensitive responses.
- May provide limited benefits when clients do not reuse cached responses.
Summary
ASP.NET Core Output Caching and Response Caching both help reduce unnecessary work, but they operate at different levels.
Use Output Caching when you want the server to reuse the results of eligible endpoint requests. Use Response Caching when you want browsers and compliant intermediaries to follow HTTP caching rules for suitable responses.
Before enabling either feature, check whether the response is public, how often the data changes, and how the application will handle expiration and invalidation.
The best caching strategy is not the one that caches the most data. It is the one that reduces unnecessary work without returning stale or private information to the wrong user.
Jasen FiciPosted Oct 29, 2026, 12:46 PM
Appreciate you writing this. It's featured in DotNetNews: https://dotnetnews.beehiiv.com/p/new-post-5a02