Blazor Render Modes Explained
This page is inspired by Patrick God's YouTube video, which I have modified and extended for this page.
Overview
Blazor has the option of several Render Modes, most notably available when creating a new project. There are:
-
Blazor Server
- Runs components on the server; UI diffs are sent over a SignalR connection to the browser.
- Fast initial download, small footprint in the browser.
- Requires persistent server connection and adds server CPU/state per connected client.
- Good when you need centralized server control, fast cold starts, or access to server resources.
-
Blazor WebAssembly (Client-side)
- Runs the .NET runtime and components in the browser via WebAssembly.
- Fully client-side interactivity after download; can work offline and scale without per-client server state.
- Larger initial download (runtime + app) and depends on browser WebAssembly support.
- Good for offline scenarios or to reduce server load.
-
Server Prerendered (RenderMode.ServerPrerendered)
- Renders initial HTML on the server and sends it to the browser, then bootstraps a SignalR connection to activate interactivity (Blazor Server).
- Faster perceived first paint and better for SEO; requires a short server round-trip to become interactive.
-
Server Interactive (RenderMode.Server)
- Renders nothing static on the page; the component is activated purely via SignalR to render once connected.
- Avoids duplicate markup but can delay visible UI until connection is established.
-
WebAssembly Prerendered (RenderMode.WebAssemblyPrerendered)
- Server renders initial HTML for fast first paint/SEO, then the browser loads the WebAssembly app which takes over client-side interactivity.
- Combines fast initial rendering with full client-side execution; adds complexity (server-side render + client bootstrap).
-
Static (RenderMode.Static)
- Renders static HTML on the server and does not attach any interactive Blazor behavior.
- Useful for content that should be static/SEO-friendly or where interactivity is not required.
Note: “Blazor Hybrid” (MAUI) is a different hosting model (native app hosting WebView) rather than a render mode; it runs components in-process and is used for native desktop/mobile apps.
Getting Started
The render mode can be first selected when creating a new Blazor Web App project:
After completing the page to name the project/solution we are predented with the Additional Information page, which allows us to choose an Interactive Render Mode:
Static Server Side Rendering
Choosing None creates a static server side rendering mode application - No Web Sockets, No WebAssembly, just plain static server side rendering, the finished (*rendered) page is sent to the client. The created project is quite small. Only the server side rendering components are added to Program.cs
using BlazorAppRenderModes.Components;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorComponents();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error", createScopeForErrors: true);
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseAntiforgery();
app.MapStaticAssets();
app.MapRazorComponents<App>();
app.Run();
NOTE: We can choose the render mode to be used for each component individually, however to define the default mode we could define this in the <HeadOutlet /> tag in the App.razor file.
** NOTE:** Inside a component (such as the example Weather.razor component), the attribute:
@attribute [StreamRendering]
Allows the page to load quickly, then dynamically load any data and update the page. If we were to remove this attribute the page would load more slowly in one shot, but only when the data has already been loaded. Static server side rendering still gives up this option. Note that most SEO tools will not pick up the data if StreamRendering is enabled.
Blazor (Interactive) Server Rendering
We can switch our current project to allow interactive server rendering by adding AddInteractiveServerComponents(); to our Program.cs file, along with AddInteractiveServerRenderMode() to the app configuration:
using BlazorAppRenderModes.Components;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error", createScopeForErrors: true);
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseAntiforgery();
app.MapStaticAssets();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();
app.Run();
This is effectively what seleting the Server render mode on the Additional Information project creation tab would have done for us.
This mode allows us to now remove the StreamRendering attribute mentioned above from the component, since this is now covered and no longer makes sense, but we have to add
@rendermode InteractiveServer
to the component in order to use websockets instead , as you can see in the browser console output:
These web sockets are automatically closed.
This works at the page (@page) and individual component level, for example:
<button @onclick="OnClick">Click me</button>
<span>@text</span>
@code {
string text = string.Empty;
private void OnClick()
{
text = "Button clicked!";
}
}
Now add this to the home page:
@page "/"
<PageTitle>Home</PageTitle>
<h1>Hello, world!</h1>
Welcome to your new app.
<MyButton />
And it will display, but nothing will happen as we have not defined an interactive render mode (Server or WebAssembly), we still only have static server side rendering on this page.
We can fix this in one of three ways, either on the page as a whole by adding the @rendermode InteractiveServer
@page "/"
@rendermode InteractiveServer
<PageTitle>Home</PageTitle>
<h1>Hello, world!</h1>
Welcome to your new app.
<MyButton />
Or on the usage of the component itself:
@page "/"
<PageTitle>Home</PageTitle>
<h1>Hello, world!</h1>
Welcome to your new app.
<MyButton @rendermode="InteractiveServer" />
So the page as a whole has no render mode defined now, but the individual component usage does...
Or by defining it in the component itself to always use this render mode:
@rendermode InteractiveServer
<button @onclick="OnClick">Click me</button>
<span>@text</span>
@code {
string text = string.Empty;
private void OnClick()
{
text = "Button clicked!";
}
}
Blazor WebAssembly
Blazor WebAssembly is more complicated to add to an existing project as you need to add an additional client project. Of course this is done automatically if you select the WebAssembly option from the Additional Information dialog during project creation.
To add this manually you need to add a new project from the solution explorer, and choose the Blazor WebAssembly Standalone App project type:
When naming the project it is good to append .client to the name, for example:
Any new WASM project created this way will have more files than if we were creating a brand new solution and selecting WebAssembly from the Additional Information tab. We can remove the following files to prune this down a little (since it will be working alongside our main project):
App.razorPagesfolder (see note below)Layoutfolderwwwrootfolder (You will probably need to close Visual Studio to delete this folder via file explorer)
Finally Update the new Program.cs file:
Remove the following two lines
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");
If you won't be needing to call APIs, etc from your Web Assembly then you could remove the following line (this would rely on the main project doing the API calls and the WASM project being a used only for the front end UI)
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
NOTE: If you want to use pages in your Web Assembly code then do not delete the Pages folder.
The main project must also have the following changes to work with the new WASM project:
- Add a new WASM Project Reference to the main (existing) project.
- Add a new (NuGet) package reference to Microsoft.AspNetCore.Components.WebAssembly.Server.
- Update the Program.cs file to include
.AddInteractiveWebAssemblyComponents()along with.AddInteractiveWebAssemblyRenderMode()and.AddAdditionalAssemblies(typeof(BlazorRenderModes.Client._Imports).Assembly)(Where BlazorRenderModes.Client. is the namespace of our WASM project):
// Add services to the container.
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents()
.AddInteractiveWebAssemblyComponents();
...
app.MapStaticAssets();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode()
.AddInteractiveWebAssemblyRenderMode()
.AddAdditionalAssemblies(typeof(BlazorRenderModes.Client._Imports).Assembly);
Now we are ready to use our WebAssembly project, so as an example we can move our Button component definition to the client project (removing it from the server project):
We can now update the Home page button reference rendermode value to InteractiveWebAssembly (along with a using statement in either this page or the _Imports.razor file):
@page "/"
<PageTitle>Home</PageTitle>
<h1>Hello, world!</h1>
Welcome to your new app.
<MyButton @rendermode="InteractiveWebAssembly" />
You should now be able to run the application.
If you follow what is happening in the console you will see that no web sockets are being used, but the sample weather page also still works as before.
AutoRender Mode
Auto render mode will render the component on the server side initially, providing a fast response/render time, whilst downloading the client side version in the background. On subsequent page/component reloads the component is rendered on the client side, resulting in no (or at least fewer) trips to the server, so a lighter server load and potentially rendering even faster locally.






