Introduction
Blazor WebAssembly lets .NET developers build browser applications using C# and .NET instead of relying entirely on JavaScript.
That approach has always involved an important trade-off: before a Blazor WebAssembly application can do meaningful client-side work, the browser needs to download the application resources, initialize the WebAssembly runtime, and load the application's assemblies.
For a small application, that startup work can become noticeable.
.NET 11 introduces improvements aimed at making Blazor WebAssembly applications smaller, which makes startup performance an interesting area to measure. Rather than assuming that a smaller application will automatically feel faster, developers should measure the complete path from the initial request to the point where the application is ready for interaction.
This article shows how to build a controlled Blazor WebAssembly benchmark, measure download size and startup timing, and identify the factors that can influence the results.
Why Blazor WebAssembly Startup Matters
A Blazor WebAssembly application generally follows a client-side startup sequence similar to this:
Browser requests application
|
v
Download HTML
|
v
Download application resources
|
v
Initialize WebAssembly runtime
|
v
Load .NET assemblies
|
v
Start Blazor application
|
v
Render UI
|
v
Application becomes interactive
Every step can contribute to the time a user waits before interacting with the application.
This is particularly important for users on:
The size of the application is therefore worth measuring, but it should not be treated as the only performance metric.
What Makes a Blazor WebAssembly Application Large?
A Blazor WebAssembly application can contain several types of resources:
A project can therefore become significantly larger simply by adding dependencies.
For example:
<ItemGroup>
<PackageReference Include="SomeLargeLibrary"
Version="1.0.0" />
</ItemGroup>
The exact impact depends on how the library is used and whether its assemblies or resources can be removed during publishing.
This is why application-size benchmarking should compare complete published applications rather than looking only at the size of the main project assembly.
Creating a Minimal Blazor WebAssembly Application
A simple application provides a useful baseline.
A Razor component might contain:
@page "/"
<PageTitle>Home</PageTitle>
<h1>Welcome</h1>
<p>This is a small Blazor WebAssembly application.</p>
<button @onclick="Increment">
Clicked @count times
</button>
@code {
private int count;
private void Increment()
{
count++;
}
}
This application intentionally has very little application logic.
That gives you a baseline before adding larger dependencies, additional pages, services, or UI components.
Publishing for a Realistic Test
Performance testing should use a published Release build.
For example:
dotnet publish -c Release
The exact target framework depends on the .NET version and project configuration being tested.
Avoid using development-server results as your primary benchmark.
A development environment can include debugging features, unoptimized resources, different caching behavior, and other tooling that does not represent a deployed application.
Measuring Download Size
The first measurement should be the total amount of data the browser needs to download.
Browser developer tools are useful for this.
Open the Network tab and reload the application.
Record:
A useful table looks like this:
| Metric | Baseline | Optimized Build |
|---|
| Total requests | Measure | Measure |
| Resource size | Measure | Measure |
| Transferred bytes | Measure | Measure |
| Largest resource | Measure | Measure |
| Initial document time | Measure | Measure |
Do not insert assumed values into a benchmark article.
The numbers depend on the application, SDK version, dependencies, hosting configuration, compression, and deployment environment.
Resource Size vs Transferred Size
This distinction is easy to miss.
Suppose developer tools show:
Resource size: 2.4 MB
Transferred: 620 KB
The browser may need to process the larger resource after receiving a compressed representation over the network.
Both measurements are useful.
Resource size tells you about the underlying application payload.
Transferred size tells you approximately how much data moved over the network.
When discussing startup performance, record both rather than reporting only one.
Measuring Startup Time
The next question is more important:
How long does the application take before the user can actually interact with it?
A simple benchmark can define a clear application-ready point.
For example, the application can mark readiness after its initial UI has rendered:
performance.mark("blazor-app-ready");
The measurement point must be consistent between builds.
You could define:
T0 = Navigation begins
T1 = Initial document loaded
T2 = Blazor startup begins
T3 = Application initialization completes
T4 = First usable UI
The exact definition matters more than the label.
If one build measures T3 and another measures T4, the comparison is invalid.
Using the Performance API
The browser Performance API can help collect timing information.
For example:
performance.mark("app-ready");
const measure = performance.measure(
"application-startup",
"navigationStart",
"app-ready"
);
console.log(
`Startup: ${measure.duration.toFixed(2)} ms`
);
This should be integrated into the application at a consistent readiness point.
For production applications, avoid writing noisy diagnostic output into the normal user experience. A telemetry system or browser performance collection mechanism is more appropriate when actual user measurements are required.
Cold Start vs Repeat Navigation
One important distinction is between a cold load and a repeat visit.
A cold load may require the browser to download application resources.
A repeat visit may benefit from:
Therefore, measure both when evaluating startup.
A simple test matrix can be:
| Test | Cache | Network | Purpose |
|---|
| Cold load | Cleared | Controlled | Initial experience |
| Warm load | Enabled | Controlled | Returning user |
| Slow network | Cleared | Throttled | Constrained connection |
| Mobile-like network | Cleared | Throttled | Realistic mobile scenario |
This produces more useful information than a single local test.
Why Smaller Apps Can Help
Reducing application payload can reduce the amount of data the browser needs to download and process.
The effect is particularly noticeable when network bandwidth or latency is limited.
But there is an important qualification.
Startup is not simply:
Startup Time = Download Time
It is closer to:
Startup
=
Network transfer
+
Resource processing
+
Runtime initialization
+
Assembly loading
+
Application initialization
+
UI rendering
Reducing download size can help one part of this process while leaving other costs unchanged.
That is why actual measurements are important.
Dependency Size Matters
A common source of unnecessary application growth is adding libraries without considering their client-side cost.
For example:
using SomeLargeLibrary;
var service = new SomeLargeService();
The code may use only a small portion of the package, but the dependency can still influence the application's published output.
Before adding a library to a WebAssembly application, ask:
Does the application actually need it?
Is there a smaller alternative?
Does it add significant client-side resources?
Can the functionality remain server-side?
Does it affect startup time?
These questions become more important for applications where initial load speed is a priority.
Benchmarking Different Application Sizes
A useful experiment is to create multiple versions of the same application.
Test A: Minimal Application
Only the framework and application code.
Test B: Application With Common Dependencies
Add the libraries normally used by the application.
Test C: Production Application
Use the complete application with its real dependency set and UI.
Then compare:
Application Size
|
+----> Transfer Time
|
+----> Resource Processing
|
+----> Runtime Initialization
|
+----> Ready Time
This helps identify whether an observed startup difference is related to payload size or another part of the startup pipeline.
Using Browser Network Throttling
A local high-speed connection can hide payload problems.
Browser developer tools allow you to simulate slower network conditions.
For example, you can compare:
The exact profiles available depend on the browser.
The important thing is to use the same profile for every build.
If the smaller application only saves a tiny amount of time on a fast desktop connection but produces a larger difference on a constrained network, that is valuable information.
Common Benchmarking Mistakes
Measuring Debug Builds
Debug builds are not suitable for production performance comparisons.
Use Release publishing.
Testing Only on Localhost
Localhost removes much of the network latency that real users experience.
Use a deployed environment or controlled network simulation when network transfer is part of the question.
Clearing Cache for Only One Test
A cold-load test and a warm-load test are different scenarios.
Keep the cache state consistent.
Changing Multiple Variables
If you change the framework version, application code, dependency set, server, compression, and hosting configuration simultaneously, you cannot identify what caused the difference.
Change one major variable at a time.
Reporting One Measurement
Browser startup measurements naturally vary.
Run multiple iterations and report the methodology alongside the results.
Troubleshooting Slow Startup
If a Blazor WebAssembly application starts slowly, inspect the browser Network tab first.
Look for:
Large assemblies.
Large JavaScript files.
Large images.
Fonts.
Slow server responses.
Missing compression.
Excessive application initialization.
Third-party libraries.
Large API requests during startup.
Unnecessary resources loaded before the first screen.
Also check whether the application is making API calls before displaying its initial UI.
For example:
protected override async Task OnInitializedAsync()
{
Products = await ProductService.GetProductsAsync();
}
If GetProductsAsync() takes several seconds and the UI waits for it before displaying useful content, reducing the WebAssembly payload alone will not solve the startup problem.
Sometimes the better solution is to render the initial shell immediately and load non-critical data afterward.
Production Considerations
A production benchmark should represent how users actually access the application.
Consider:
Do not optimize only for the fastest development machine.
Also remember that a smaller application is not automatically a better application.
Removing a useful dependency simply to save a few kilobytes may create more maintenance problems than it solves.
Optimization should be driven by measurable user impact.
Best Practices
Measure the Complete Startup Path
Do not focus only on WebAssembly download size.
Measure the time until the application becomes useful.
Keep a Baseline
Before making optimization changes, record the existing application's size and startup measurements.
Without a baseline, it is difficult to determine whether an optimization actually helped.
Test Cold and Warm Loads
Both are important for understanding the experience of new and returning users.
Use Production Builds
Always benchmark published Release output.
Watch Dependency Growth
Review the client-side impact of major dependencies before adding them.
Optimize the Critical Path
Not every resource needs to be loaded before the first interaction.
Move non-critical work out of the initial startup path where the application architecture allows it.
Advantages
Smaller WebAssembly applications can reduce network transfer requirements.
Reduced client payload can be particularly useful on constrained connections.
A smaller dependency graph can make client-side applications easier to analyze.
Startup measurements provide concrete data for optimization decisions.
Blazor allows developers to investigate performance using familiar .NET tooling alongside browser diagnostics.
Disadvantages
Smaller payloads do not automatically eliminate runtime startup costs.
Performance varies significantly by device and network.
Aggressive dependency reduction can make application development harder.
Localhost measurements can hide real-world network costs.
Browser caching can make repeat-load results look very different from cold-load results.
Conclusion
Blazor WebAssembly startup performance should be treated as a complete pipeline rather than a single download-size number.
Application payload size matters, especially on slower networks, but the browser must also initialize the WebAssembly runtime, load assemblies, execute application startup code, and render the first usable interface.
The most reliable way to evaluate improvements is to create a baseline, publish the application in Release mode, measure resource and transferred sizes, and record startup timing under controlled conditions.
Test both cold and warm loads, use consistent network conditions, and compare the same application across builds.
The result is a much more useful performance picture than simply saying that one build is "smaller." A smaller application is valuable when that reduction translates into a better experience for the users who actually run it.