Blazor WebAssembly Performance: 12 Optimizations

Blazor WebAssembly is the only mainstream framework that lets you ship C# directly to the browser. The trade-off is that the .NET runtime has to ship with your application — and an unoptimized Blazor WASM build can easily exceed 3 MB compressed, with first-paint times north of 4 seconds on mid-tier mobile.

That's a deal-breaker for public-facing applications. But it's also entirely avoidable. Here are twelve techniques we apply to every production Blazor WebAssembly deployment, with measurements from real customer applications.

900 KB | Optimized Payload

1.1 s | First Paint (4G)

2.8 s | Time to Interactive

12 | Proven Techniques

Baseline: What "Slow" Blazor WASM Actually Looks Like

Before optimizing, you have to measure. Our default benchmark target on the Blazor WebAssembly hosting plan:

| Metric | Target | Default Build |

|---|---|---|

| First Contentful Paint (4G) | 💡 Trade-off: AOT increases bundle size 30–50% but improves CPU-bound code execution 2–10×. Use it for apps with heavy client-side logic (data grids, image manipulation, charting). Avoid it for thin UI shells that mostly call APIs.

2. Aggressive Trimming

The default trim mode in .NET 9 is partial — safe but leaves a lot on the table. Switch to full trimming for production:

<PublishTrimmed>true</PublishTrimmed>

<TrimMode>full</TrimMode>

Then mark types that use reflection with [DynamicallyAccessedMembers] or use the TrimmerRoot directive to keep them. We see 20–40% bundle reduction on most applications.

3. Lazy Load Routes

If your app has admin pages, dashboards, or settings screens that only a fraction of users visit, lazy-load them. Mark assemblies for deferred load in the .csproj:

<ItemGroup>

<BlazorWebAssemblyLazyLoad Include="Admin.dll" />

<BlazorWebAssemblyLazyLoad Include="Charts.dll" />

</ItemGroup>

Then load on demand:

var assemblies = await LazyAssemblyLoader.LoadAssembliesAsync(

new[] { "Admin.dll" });

> 🚀 Highest-leverage win: This is the single biggest optimization for most apps. A 5 MB Blazor app can drop to 1.5 MB initial payload while keeping full functionality. Pair it with route-based code splitting.

4. Brotli Compression on the Server

Blazor WebAssembly publishes .br versions of every asset by default, but you need a server that serves them. On Adaptive's Blazor hosting, IIS 10 is preconfigured to serve .br to browsers that send Accept-Encoding: br, falling back to .gz and then identity.

Brotli compresses Blazor's DLLs 15–25% better than gzip. On a 1.5 MB Blazor app, that's an extra 200–300 KB saved per first-load.

5. Prerender on the Server

Server-side prerendering renders the initial HTML on the server (via .NET on IIS), then hydrates client-side after the WASM runtime loads. The user sees content immediately; LCP drops dramatically.

<component type="typeof(App)" render-mode="WebAssemblyPrerendered" />

Trade-off: your app has to be SSR-safe (no direct DOM access at startup). Most apps already are.

6. Defer Non-Critical CSS and JS

Move analytics, chat widgets, and tracking scripts to ` or . They block neither HTML parsing nor your Blazor bootstrap.

For CSS, inline critical above-the-fold styles in and load the rest with media="print" onload="this.media='all'" — a classic non-blocking pattern.

7. Optimize the Dotnet.wasm Runtime Itself

Add these properties to your project file:

<WasmStripILAfterAOT>true</WasmStripILAfterAOT>

<BlazorWebAssemblyEnableLinkerOptimization>true</BlazorWebAssemblyEnableLinkerOptimization>

WasmStripILAfterAOT removes the .NET IL after AOT compilation completes — saving 200–500 KB if you've enabled AOT.

8. Virtualize Long Lists

Blazor 9 ships , which renders only the visible portion of long lists. For data grids with 1000+ rows, this turns 200 ms render times into 5 ms render times.

<Virtualize Items="@orders" Context="order">

<OrderRow Order="@order" />

</Virtualize>

!Performance comparison chart

9. Use ImageSharp.Web for Adaptive Images

Serve WebP/AVIF on supported browsers, with size variants generated on demand. ImageSharp.Web integrates as ASP.NET Core middleware; our IIS configuration includes the required modules.

A 200 KB hero image becomes 35 KB AVIF — saving on a metric that affects LCP directly.

10. Cache the .NET Runtime in Service Workers

The default Blazor WASM template ships a service-worker.published.js that caches dotnet.wasm and DLL assets. Verify it's active in production (DevTools → Application → Service Workers). Returning users load your app in milliseconds because the runtime is already cached.

11. Use HTTP/3 End-to-End

Behind Cloudflare's HTTP/3-enabled edge plus our QUIC-enabled IIS 10, your assets get HTTP/3 connection multiplexing and 0-RTT resumption. Particularly important for the dozens of parallel DLL requests on first load.

12. Measure With Lighthouse and Real-User Metrics

Synthetic Lighthouse runs are useful, but they don't capture variability. Wire up Real User Monitoring (RUM) — we recommend the web-vitals JavaScript library — and ship metrics to your analytics endpoint. You'll catch regressions Lighthouse misses.

Putting It All Together: A Reference Build Config

For a typical production Blazor WebAssembly app, your .csproj should look like:

<PropertyGroup>

<TargetFramework>net10.0</TargetFramework>

<RunAOTCompilation>true</RunAOTCompilation>

<PublishTrimmed>true</PublishTrimmed>

<TrimMode>full</TrimMode>

<WasmStripILAfterAOT>true</WasmStripILAfterAOT>

<BlazorWebAssemblyEnableLinkerOptimization>true</BlazorWebAssemblyEnableLinkerOptimization>

<BlazorEnableCompression>true</BlazorEnableCompression>

</PropertyGroup>

<ItemGroup>

<BlazorWebAssemblyLazyLoad Include="Admin.dll" />

<BlazorWebAssemblyLazyLoad Include="Reports.dll" />

</ItemGroup>

Add prerendering at the host project layer, deploy to a Blazor-optimized host, and you'll typically land around:

> ✅ Measured results from production customer apps:

> - 900 KB compressed initial payload

> - 1.1 s First Contentful Paint

> - 1.9 s Largest Contentful Paint

> - 2.8 s Time to Interactive

These are not hypothetical numbers — they're what we measure on customer applications today.

Hosting Considerations Most Optimization Guides Skip

A perfectly optimized Blazor WebAssembly build will still be slow on a host that doesn't serve compressed responses, doesn't enable HTTP/2 push or HTTP/3, or sits on the wrong continent from your users.

| Hosting Feature | Why It Matters | Default on Adaptive? |

|---|---|---|

| Brotli + gzip negotiation | Saves 15-25% on first load | ✅ Yes |

| HTTP/2 server push | DLL manifest preload | ✅ Yes |

| HTTP/3 + QUIC | 15-20% tail latency improvement | ✅ Yes (Cloudflare edge) |

| AWS Virginia origin | ⚠️ Watch out: Many "Blazor hosting" providers run on shared Linux containers with .NET as a sidecar. Cold starts on those can exceed 5 seconds because the runtime has to be re-initialized on every request burst.

If you're running Blazor Server instead, see our Blazor Server vs WebAssembly hosting guide for the trade-offs.

Frequently Asked Questions

Does AOT make sense for every Blazor WebAssembly app?

No. AOT adds 30–50% to bundle size in exchange for 2–10× faster code execution. If your app is CPU-bound (charting, data grids, image processing), enable it. If it's a thin UI calling APIs, skip it — the larger bundle hurts more than the runtime savings help.

Will trimming break my reflection-heavy code?

Possibly. Anything that uses Activator.CreateInstance, Type.GetType, or attribute-based reflection needs trimmer hints. Annotate with [DynamicallyAccessedMembers] or mark types as TrimmerRoot. Test thoroughly in Release` configuration.

Can I run Blazor WebAssembly without a backend?

Yes — Blazor WebAssembly Standalone is a single static site, hostable on any CDN or web server. But for forms, auth, and data, you'll want an ASP.NET Core backend on the same host. Our Blazor hosting plans include both.

How big is too big for a Blazor WASM bundle?

Aim for <1.5 MB compressed initial payload. Above 3 MB, mobile users start abandoning. With AOT enabled, watch the trade-off carefully and consider per-route lazy loading.

What about Blazor Auto mode in .NET 8+?

Blazor Auto starts in Server mode for fast first paint, downloads WASM in the background, then switches modes. You get both modes' strengths if your app is structured to allow it — see our Blazor Server vs WebAssembly comparison.

title: Ship Faster Blazor WebAssembly Apps

description: Adaptive's Blazor hosting ships preconfigured for AOT, Brotli, HTTP/3, and aggressive caching. Dedicated IIS app pools, real SQL Server 2022, 99.99% uptime SLA.

cta-primary: Blazor WebAssembly Hosting | /blazor-wasm-hosting

cta-secondary: Compare Plans | /blazor-hosting-plans

Optimization techniques only land if your hosting platform supports them. Our Blazor WebAssembly hosting ships preconfigured for everything in this guide. Plans from $9.49/mo with a 30-day money-back guarantee. Talk to a Blazor specialist about migrating your existing app — or read real customer case studies.

Back to Blog