Blazor performance problems are rarely mysterious. They almost always come down to one of three things: too much shipped on first load, components that re-render when they should not, or work done on the UI thread that belongs elsewhere. This is the checklist we actually run when a Blazor app feels sluggish, organized by where the time goes.
First load
The first impression is the download. Trim it ruthlessly:
- Measure the payload before optimizing. Look at what is actually shipped on first request - you cannot fix what you have not measured.
- Lazy-load non-critical assemblies. Features behind a route the user may never visit should not be in the initial bundle.
- Defer non-essential scripts and styles. The hero content should render before the analytics script loads.
- Prerender where it helps. Server-side prerendering gives the user meaningful content before interactivity arrives.
Render efficiency
Most runtime jank is unnecessary re-rendering. Blazor re-renders a component when its parameters change or an event fires, and a careless tree re-renders far more than it needs to:
- Override
ShouldRenderon hot components to skip renders when nothing relevant changed. - Use
@keyin lists so the diff can match items instead of rebuilding rows. - Pass stable parameters. Allocating a new lambda or object every render forces children to re-render even when the data is identical.
protected override bool ShouldRender()
{
// only re-render when the values that affect output actually changed
return _lastValue != CurrentValue;
}
Tip: Before optimizing renders, turn on render diagnostics and watch which components re-render on an interaction. The culprit is usually a parent re-rendering its whole subtree over a trivial change.
Runtime responsiveness
The UI thread should do UI work and nothing else:
- Keep event handlers thin. Offload real work and update the UI when it completes, rather than blocking the handler.
- Virtualize long lists. Rendering ten thousand rows when twenty are visible is wasted work; the
Virtualizecomponent renders only what is on screen. - Debounce high-frequency input. A search box that queries on every keystroke renders on every keystroke - debounce it.
- Dispose what you subscribe to. Leaked event subscriptions and timers keep components alive and quietly degrade a long-lived session.
Measure, change, measure again
The meta-rule behind the whole list: never optimize on a hunch. Capture a baseline, make one change, and confirm it helped before moving on. Performance work guided by guesses tends to add complexity without moving the number, and the only way to know is to measure on both sides of every change.
Wrapping up
Blazor rewards working with its model rather than against it. Trim the first-load payload, stop unnecessary re-renders with ShouldRender and @key, keep the UI thread free with virtualization and debouncing, and let measurement - not intuition - drive every change. Run this checklist when an app feels slow and the sluggishness usually traces back to one or two items on it.
Want a performance review of your Blazor app? Get in touch.
