---
name: blazor-performance
description: Blazor rendering optimization, virtualization, lazy loading, caching, and memory management
allowed-tools:
- Read
- Write
- Edit
- Grep
triggers:
- blazor performance
- blazor slow
- rendering optimization
- virtualize
- lazy loading
- blazor caching
---
# Blazor Performance Optimization
## Rendering Optimization
### Use @key for list rendering
```razor
@foreach (var item in Items)
{
}
```
### Override ShouldRender
```csharp
private bool _shouldRender = true;
protected override bool ShouldRender() => _shouldRender;
```
### Virtualize large lists
```razor
@* With item provider for server-side paging *@
@code {
private async ValueTask> LoadItems(
ItemsProviderRequest request)
{
var result = await Service.GetPagedAsync(request.StartIndex, request.Count);
return new ItemsProviderResult(result.Items, result.TotalCount);
}
}
```
### Streaming SSR for slow data
```razor
@attribute [StreamRendering]
@if (_data is null)
{
}
else
{
}
```
## Caching Strategies
### Output Caching (API endpoints)
```csharp
app.MapGet("/api/products", async (AppDbContext db) =>
await db.Products.AsNoTracking().ToListAsync())
.CacheOutput(policy => policy.Expire(TimeSpan.FromMinutes(5)).Tag("products"));
```
### Distributed Cache (Redis)
```csharp
public sealed class CachedProductService(
IProductRepository repo,
IDistributedCache cache) : IProductService
{
public async Task GetByIdAsync(int id, CancellationToken ct)
{
var cacheKey = $"product:{id}";
var cached = await cache.GetStringAsync(cacheKey, ct);
if (cached is not null)
return JsonSerializer.Deserialize(cached);
var product = await repo.GetByIdAsync(id, ct);
if (product is not null)
{
await cache.SetStringAsync(cacheKey,
JsonSerializer.Serialize(product),
new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10) },
ct);
}
return product;
}
}
```
### Memory Cache for component state
```csharp
@inject IMemoryCache Cache
@code {
protected override async Task OnInitializedAsync()
{
_categories = await Cache.GetOrCreateAsync("categories", async entry =>
{
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1);
return await CategoryService.GetAllAsync();
});
}
}
```
## WASM Size Optimization
- Enable trimming: `true`
- Enable AOT compilation: `true`
- Use lazy assembly loading for rarely-used features
- Minimize NuGet packages in WASM project
## SignalR Connection (Blazor Server)
- Monitor circuit count with Aspire dashboard
- Set reasonable circuit timeout: `CircuitOptions.DisconnectedCircuitRetentionPeriod`
- Minimize state stored in circuit (use external state stores)
- Use `@rendermode InteractiveAuto` for high-traffic pages to offload to WASM