
HybridCache in ASP.NET Core – A Better Way to Handle L1 & L2 Caching
As applications grow, performance bottlenecks usually show up around repeated data access. Database queries, expensive computations, and external API calls can quickly slow things down.
Caching helps, but managing multiple cache layers often turns into messy code.
HybridCache in ASP.NET Core simplifies this by combining in-memory (L1) and distributed (L2) caching into a single, easy-to-use API.
Instead of writing separate logic for each layer, HybridCache handles everything behind the scenes.
What is HybridCache?
HybridCache is a modern caching abstraction introduced in .NET 9. It provides a unified way to work with both in-memory and distributed caching, without manually coordinating between them.
Traditionally, developers had to:
- Use
IMemoryCachefor fast access - Use
IDistributedCachefor shared storage - Write custom logic to keep them in sync
HybridCache removes that complexity completely.
How HybridCache Improves Caching
The key idea behind HybridCache is simple but powerful.
Instead of choosing between memory or distributed cache, it uses both intelligently:
- First, it checks L1 cache (in-memory)
- If not found, it checks L2 cache (distributed)
- If still not found, it fetches data from the source
- Then it stores the result in both layers
This approach gives:
- Very fast responses for repeated requests
- Shared caching across multiple instances
- Reduced load on databases and external services
It also helps prevent common issues like cache stampede, because the data factory runs only once per key.
Understanding L1 and L2 Cache Clearly
HybridCache is built around two cache layers.
- L1 (In-Memory Cache) lives inside the application process. It is extremely fast and ideal for frequent reads. However, it is limited to a single instance.
- L2 (Distributed Cache) is shared across multiple instances. It ensures consistency in load-balanced or cloud environments, even though it is slightly slower than memory.
By combining both, HybridCache ensures:
- Fast access (L1)
- Consistency across instances (L2)
Installing Required NuGet Packages
Start by adding the Microsoft.Extensions.Caching.Hybrid package:
dotnet add package Microsoft.Extensions.Caching.HybridIf planning to use distributed caching (recommended for production), install a provider such as Redis:
dotnet add package Microsoft.Extensions.Caching.StackExchangeRedisConfiguring HybridCache in ASP.NET Core
Register HybridCache in the application:
builder.Services.AddHybridCache();At this point, only L1 cache is active. However, the AddHybridCache extension method also provides an overload that allows configuring behavior such as item size limits, key limits, default expiration settings, compression, and metrics.
This is useful when more control is needed in production environments.
builder.Services.AddHybridCache(options =>
{
options.MaximumPayloadBytes = 1024 * 10 * 10;
options.MaximumKeyLength = 256;
options.DefaultEntryOptions = new HybridCacheEntryOptions
{
Expiration = TimeSpan.FromMinutes(30),
LocalCacheExpiration = TimeSpan.FromMinutes(30)
};
options.ReportTagMetrics = true;
options.DisableCompression = true;
});Let’s walk through what each option does and why it matters.
MaximumPayloadBytes– This setting controls the largest allowed cache item size in bytes. In the example above, This allows items up to roughly 10 MB. By default, HybridCache uses a smaller limit (around 1 MB). If an item exceeds the configured limit, HybridCache will skip storing that entry and log the event.
MaximumKeyLength– This controls the maximum length of a cache key. The default value is 1024 characters, but reducing it encourages cleaner and predictable key naming.
DefaultEntryOptions– This setting allows defining default expiration behavior for all cache entries. There are two important parts here:- Expiration controls how long the item remains in the distributed L2 cache.
- LocalCacheExpiration controls how long the item remains in the local in-memory L1 cache.
ReportTagMetrics– This option enables metrics related to tags.
DisableCompression– This setting controls payload compression. When compression is enabled, HybridCache can reduce payload size before storing certain entries, which may help with distributed cache network traffic.
To enable L2 cache, configure a distributed provider:
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = "localhost:6379";
});Available L2 Cache Providers
HybridCache works on top of ASP.NET Core’s distributed caching system, which means it supports any provider implementing IDistributedCache.
Common L2 cache options include:
- Redis (StackExchange.Redis) – most popular choice for production
- SQL Server Cache – useful when Redis is not available
- PostgreSQL Cache – good option in Postgres-based systems
- NCache – enterprise distributed cache solution
Get or Set Cache with HybridCache
One of the most useful features of HybridCache is the get-or-set pattern. This means the application first tries to read data from cache. If the data is not available, HybridCache runs the data factory method, gets fresh data from the source, stores it in cache, and returns it.
This removes the need to manually write separate “check cache, load data, then store cache” logic.
app.MapGet("/users/{userId:int}/dashboard/stats", async (
int userId,
HybridCache cache,
CancellationToken ct) =>
{
var stats = await cache.GetOrCreateAsync(
$"analytics-user-{userId}-dashboard",
async token =>
{
await Task.Delay(150, token); // simulate DB call
return new
{
UserId = userId,
TotalOrders = 42,
PendingOrders = 5,
Revenue = 24850
};
},
cancellationToken: ct);
return Results.Ok(stats);
});Controlling Expiration for Better Freshness
Cache expiration ensures that data does not become outdated.
app.MapGet("/users/{userId:int}/dashboard/stats", async (
int userId,
HybridCache cache,
CancellationToken ct) =>
{
var stats = await cache.GetOrCreateAsync(
$"analytics-user-{userId}-dashboard",
async token =>
{
await Task.Delay(150, token); // simulate DB call
return new
{
UserId = userId,
TotalOrders = 42,
PendingOrders = 5,
Revenue = 24850
};
},
options: new HybridCacheEntryOptions
{
Expiration = TimeSpan.FromMinutes(10),
LocalCacheExpiration = TimeSpan.FromMinutes(5)
},
cancellationToken: ct);
return Results.Ok(stats);
});In this:
- L1 local cache lives for 5 minutes
- L2 distributed cache lives for 10 minutes
Removing Cache Entries
When underlying data changes, cached data must be invalidated.
await cache.RemoveAsync("analytics-user-42-dashboard", ct);This removes the entry from both L1 and L2 layers.
Removing Cache Using Tags
Tag-based invalidation is very useful when multiple cache entries depend on the same data.
var summary = await cache.GetOrCreateAsync(
$"notifications:summary:{userId}",
async ct => await BuildNotificationSummary(ct),
tags: ["notifications"]);Later, all related entries can be removed in one call:
await cache.RemoveByTagAsync("notifications", ct);This is much cleaner than tracking individual keys.
Why HybridCache Matters in Distributed Systems
In single-instance apps, in-memory cache might be enough.
But in real-world systems with multiple instances:
- Each instance has its own memory cache
- Cache misses increase
- Data becomes inconsistent
With L2 cache enabled, HybridCache ensures:
- Shared cache across all instances
- Reduced duplicate work
- Better scalability
This makes it a strong fit for cloud-native applications.
Best Practices for Using HybridCache
HybridCache simplifies caching, but good practices still matter.
Use clear and consistent cache keys to avoid confusion. Always define expiration to prevent stale data. Use tags when multiple entries depend on the same dataset.
Avoid caching data that changes very frequently, because the overhead may outweigh the benefits.
When HybridCache is a Good Fit
HybridCache works best in read-heavy scenarios where the same data is requested multiple times.
It is commonly used for:
- Dashboard data
- Aggregated reports
- Frequently accessed user data
- Configuration and lookup data
It may not be suitable for real-time systems where data changes constantly.
Summary
HybridCache is a powerful addition to ASP.NET Core that simplifies multi-layer caching. By combining L1 and L2 caching into a single abstraction, it improves performance while keeping code clean and maintainable.
It removes the need for custom cache coordination logic and provides built-in support for expiration, tagging, and distributed caching.
Takeaways
- HybridCache is introduced in .NET 9
- Combines L1 (in-memory) and L2 (distributed) caching
- Automatically manages cache layering
- Supports multiple L2 providers like Redis and SQL Server
- Provides simple APIs for get, remove, and tag-based invalidation
- Ideal for scalable and read-heavy applications
