Blazor WASM vs Server vs Hybrid: Which Render Mode Should You Use?
A clear decision guide to Blazor render modes: Static SSR, Interactive Server, Interactive WebAssembly, and Auto, plus Blazor Hybrid and how to choose.
Blazor gives you four render modes and a Hybrid option, and the names don’t make the choice straightforward. For those familiar with Blazor, the previous split between “Blazor Server” and “Blazor WebAssembly” projects is gone. Since .NET 8, a Blazor Web App is one app that picks a render mode per page, or per component. This post explains each mode, its trade-offs, and when to pick it.
Razor vs Blazor
First, for those new to .NET, a common question I get asked: what’s the difference between Razor and Blazor? (They both end in “azor” so they have to be the same thing, right?)
Razor is the templating syntax, the mix of HTML and C# you write in .razor and .cshtml files. Blazor is the UI
framework that takes Razor components and makes them interactive, on the server, in the browser
through WebAssembly, or inside a native app. For the syntax itself,
I covered what Razor is separately. The rest of this post is about Blazor render modes.
One app, four render modes
The previous model gave you two project types, “Blazor Server” and “Blazor WebAssembly,” and you picked one up front. The latest model gives you a single Blazor Web App, and every component adopts a render mode that decides where it runs and whether it’s interactive.
There are four:
| Render mode | Where it runs | Interactive? |
|---|---|---|
| Static Server (static SSR) | Server | No |
| Interactive Server | Server, over SignalR | Yes |
| Interactive WebAssembly | Browser, WASM | Yes |
| Interactive Auto | Server first, then browser | Yes |
You set a render mode with the @rendermode directive. On a page definition:
@page "/dashboard"@rendermode InteractiveServer
<h1>Dashboard</h1>Or on a single component instance, so one page can mix modes:
<Weather @rendermode="InteractiveServer" /><Chart @rendermode="InteractiveWebAssembly" />The Blazor Web App template adds @using static Microsoft.AspNetCore.Components.Web.RenderMode to _Imports.razor, which is why you can write InteractiveServer instead of the full RenderMode.InteractiveServer.
You enable the interactive modes in Program.cs. This turns on all three:
builder.Services.AddRazorComponents() .AddInteractiveServerComponents() .AddInteractiveWebAssemblyComponents();
// ...
app.MapRazorComponents<App>() .AddInteractiveServerRenderMode() .AddInteractiveWebAssemblyRenderMode();Anything using Interactive WebAssembly or Auto must live in a separate client project, the one whose name ends in .Client, so it compiles into the downloadable bundle. The template sets this up when you opt into WebAssembly interactivity.
Prerendering is on by default for the interactive modes, so the server paints the initial HTML either way and the component becomes interactive once its runtime is ready.
Interactive Server
Interactive Server renders the component on the server and keeps a real-time SignalR connection, called a circuit, open to the browser. Each click and keystroke travels to the server, which runs your C#, diffs the UI, and sends back the changes.
What you get:
- Almost nothing to download, so the app is interactive right away.
- Direct access to your database, secrets, and internal services, with no API layer in between.
- The normal server-side debugging experience.
The trade-offs:
- Every interaction is a network round trip, so latency may be a (negative) factor users on slow connections.
- The server holds UI state for every active circuit, which costs memory and turns scaling into a capacity question.
- A dropped connection stalls the UI until it reconnects, and offline doesn’t work.
Pick Interactive Server when your users are close to your server, such as internal line-of-business apps and admin tools, and you want the shortest path to running C# end to end.
Interactive WebAssembly
Interactive WebAssembly runs the component in the browser. The .NET runtime and your app bundle download once, get cached, and after that your C# runs client-side with no server round trip for UI events.
What you get:
- Instant interactions after load, because they run locally.
- Offline support, PWA packaging, and static hosting on a CDN.
- Less server load, since the client does the work.
The trade-offs:
- The first visit pays for the runtime download and a cold start, so initial load is slower.
- You’re bound by the client’s resources.
- Nothing in the browser is secret. Keep connection strings, API keys, and privileged logic out of client code and behind an API, the same as a JavaScript SPA.
If you run into problems, my notes on debugging Blazor WASM may help.
Pick WebAssembly when you need offline support, want to cut server cost, or are building something CDN-friendly and app-like.
Interactive Auto
Auto combines the other two. On the first visit, the component renders with Interactive Server, so the user gets interactivity immediately. The WebAssembly runtime and bundle download in the background and cache. On the next visit, the component runs client-side.
@page "/counter"@rendermode InteractiveAuto
<button @onclick="() => count++">Clicked @count times</button>
@code { private int count;}You get a fast first load and, over time, the responsiveness and server offload of WebAssembly. Two things to know. Auto decides per component when that component first loads, and it keeps that choice while the component stays on the page, so it won’t switch modes mid-session. And because the same component can run on the server or the client, your code has to work in both places, which rules out server-only dependencies.
Auto is a good default for general-purpose apps that want a fast first load without giving up WebAssembly later.
Static SSR
Not everything needs to be interactive. As a long-time static site lover (this blog for example), I prefer this option.
Static Server rendering emits HTML with no circuit, no WASM, and no event handling. It’s the default when a component
doesn’t set a mode, and it fits content-first pages: marketing pages, blog posts, docs, anything a search engine should read. You can still drop an interactive island into a static page by giving one child component a @rendermode, or add client-side behavior to static output with a library like htmx. Where plain HTML works, it’s faster and cheaper than interactivity.
Coming in .NET 11, static SSR handles more than it used to. Forms get instant in-browser validation without a server round trip or a WebAssembly download, enabled by default for any static SSR form with a DataAnnotationsValidator. QuickGrid also gains URL-based paging and sorting through query strings, so a data grid no longer forces an interactive render mode. Both close common gaps that used to push people toward Interactive Server or WebAssembly. If you handle form posts directly, I covered plain HTML forms and antiforgery in Blazor SSR separately.
Blazor Hybrid
Everything above assumes a browser. Blazor Hybrid doesn’t. Here your Razor components run inside a native app, a .NET MAUI app on Windows, macOS, iOS, or Android, rendered by a BlazorWebView control. There’s no WebAssembly and no SignalR circuit. The components execute directly in the app’s .NET process with full access to native device features and the local filesystem.
Hybrid reuses your Blazor components and C# to ship a native application instead of a web one. If you’re building an installable desktop or mobile app, Hybrid fits. If it lives at a URL, use one of the web render modes.
Picking a mode
| Your situation | Reach for |
|---|---|
| Content-first, SEO-driven pages | Static SSR |
| Internal app, users near the server, direct data access | Interactive Server |
| Offline support, PWA, CDN hosting, low server cost | Interactive WebAssembly |
| Fast first load and client-side speed | Interactive Auto |
| Installable desktop or mobile app built with web skills | Blazor Hybrid |
In a Blazor Web App these aren’t exclusive. One app can serve a static marketing page, an Interactive Server admin panel, and an Auto-rendered dashboard. You choose per page or per component, and you can change your mind later by editing a directive instead of rebuilding the project.
Thanks for reading and sharing my posts with friends and colleagues. Cheers.
Around the web
Comments
Loading comments from GitHub Discussions…