Reducing Blazor WebAssembly Startup Time with Lazy Assembly Loading
Optimize Blazor WebAssembly startup times by deferring heavy assemblies. Learn how to use BlazorWebAssemblyLoadOnDemand to reduce initial payload size.
07 Aug 2025, 13:29 UTC

The Problem: The "Heavy" Initial Payload
Blazor WebAssembly (WASM) applications typically download all referenced .NET assemblies during the initial boot process. While this ensures a seamless experience once the app starts, it creates a significant barrier for first-time users. If your project includes large third-party libraries—such as complex data grids, charting engines, or heavy PDF generators—the initial download size can swell to several megabytes, leading to long loading screens and poor user retention on slower connections.
Thesis: Defer Non-Essential Code via On-Demand Loading
To optimize startup performance, you can move non-essential features into separate assemblies and defer their download until the user actually needs them. By utilizing the Blazor.WebAssembly.LoadAssemblyOnDemand JavaScript API, you can shift the cost of heavy libraries from the initial page load to a specific user action, such as clicking a "Reports" tab or opening a detailed editor.
Configuring Assemblies for Lazy Loading
To prevent an assembly from being bundled into the initial payload, you must explicitly tell the build system to treat it as an on-demand resource. This is typically handled in the project file (.csproj) of the main Blazor WASM project.
- Isolate the Feature: Move the heavy components or logic into a separate Razor Class Library (RCL). For example, create a project named
App.Features.Charts. - Mark for Lazy Loading: In the main project file, add the assembly to the
BlazorWebAssemblyLoadOnDemanditem group. This prevents the compiler from including it in the default boot sequence:<ItemGroup> <BlazorWebAssemblyLoadOnDemand Include="App.Features.Charts.dll" /> </ItemGroup> - Verify Output: Ensure the DLL is present in the
wwwroot/_framework/directory after build, as the browser will need to fetch it from this relative path at runtime.
Worked Example: Loading a Component on Demand
The following example demonstrates how to trigger the download of a lazy-loaded assembly when a user clicks a button. This requires a small amount of JavaScript interop to call the Blazor runtime API.
Step 1: The JavaScript Helper
Add this function to your index.html or a separate JS file to wrap the Blazor API in a Promise that your C# code can await:
window.loadAssembly = async (assemblyPath) => {
return await Blazor.WebAssembly.LoadAssemblyOnDemand(assemblyPath);
};
Step 2: The Blazor Component
In your main page, use IJSRuntime to trigger the load. Note that you must handle the loading state to prevent the UI from appearing frozen.
@inject IJSRuntime JS
@if (_isLoaded) {
<ChartComponent />
} else {
<button @onclick="LoadChart" disabled="@(_isLoading)">
@(_isLoading ? "Loading..." : "View Analytics")
</button>
}
@code {
private bool _isLoaded = false;
private bool _isLoading = false;
private async Task LoadChart() {
_isLoading = true;
try {
// Path relative to the _framework folder
await JS.InvokeVoidAsync("loadAssembly", "_framework/App.Features.Charts.dll");
_isLoaded = true;
} catch (Exception ex) {
Console.WriteLine($"Error loading assembly: {ex.Message}");
} finally {
_isLoading = false;
}
}
}
Trade-offs and Limitations
- UI Complexity: You can no longer assume a component is available at startup. You must implement loading indicators (spinners) and error boundaries to handle network failures during the on-demand fetch.
- Runtime Constraints: You cannot lazy-load core .NET runtime assemblies or the Blazor framework itself; doing so will crash the application during the boot process.
- Latency Shifts: You aren't removing the download cost, only moving it. If a user interacts with every lazy-loaded feature immediately, they will experience multiple small pauses instead of one large initial wait.
Practical Verification
To verify the implementation is working and not simply caching the DLL, follow these steps:
- Open Browser DevTools (F12) and navigate to the Network tab.
- Check the Disable Cache checkbox.
- Refresh the page and observe the initial list of
.dllfiles. The lazy-loaded assembly (e.g.,App.Features.Charts.dll) should not appear in this initial list. - Click the trigger button in the UI. You should see a new network request for the specific DLL appear exactly at the moment of the click.
Actionable Closing
Audit your Blazor WASM application's initial load size using the Network tab. Identify any library that is used in fewer than 50% of user sessions or only in specific sub-pages. Move those dependencies into a separate Razor Class Library, mark them with BlazorWebAssemblyLoadOnDemand, and implement a loading state in your UI. This targeted approach ensures your app remains responsive for new users while maintaining full functionality for power users.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.