Circuits, State and Reconnection in Blazor Server

What a circuit really holds, why a dropped connection is not a lost session, and how to keep state that survives both.
A circuit is a conversation
A Blazor Server circuit is the server-side object graph backing one browser tab. It holds your component instances, their fields, and the render tree used to diff the next update. It does not hold anything the browser owns.
What lives where
- Circuit memory - component fields, injected scoped services, cascading values.
- Browser memory - form input the user is typing, scroll position, focus.
- Durable storage - anything you cannot afford to lose.
The mistake is assuming category two and three are the same as category one.
public sealed class DraftState
{
private readonly ProtectedLocalStorage storage;
public DraftState(ProtectedLocalStorage storage) => this.storage = storage;
public ValueTask SaveAsync(string key, string body)
=> storage.SetAsync(key, body);
}
Reconnection
When the WebSocket drops, Blazor shows the reconnect overlay and tries to reattach to the same circuit. If the server still has it, the page resumes mid-edit. If the server recycled, restarted or evicted it, the user gets a full reload and everything in circuit memory is gone.
Treat circuit memory as a cache with an unpredictable eviction policy, because that is precisely what it is.
Practical rules
- Persist anything a user typed to
ProtectedLocalStorageon a debounce. - Keep per-circuit memory small; you pay for it per open tab.
- Set
DisconnectedCircuitRetentionPerioddeliberately instead of accepting the default. - Never store a
DbContextor an open connection in a component field.
Next: scaling SignalR, where one server stops being enough.
More Posts
Comments (0)
No comments yet
Be the first to share your thoughts on this post.
Leave a comment
No account needed — just your name and email.