Skip to content

The Duel

One app. The same .razor sources. Two compilers.

A routed task board (EditForm add, keyed list with per-row toggle/remove, filters, LINQ stats, a second page), compiled once byBlazor WebAssembly and once byFilament, from thesame page files. Every number below was taken only after a10-step behavioural contract (add, toggle a persisting row, all three filters, per-row remove, navigate, remount afresh, Back) passed identically on both sides.

Weight on the wire

403× less to download

Cold cache, service workers blocked, every byte counted by CDP from navigation until the app is interactive and the network idle. Brotli negotiated, as production would.

Time to interactive

6.7× sooner (over localhost)

Navigation to the app answering its ready probe, the instant observed in-page by a MutationObserver, never a frame boundary. Median of 10 cold loads. Localhost flatters the heavier side: on a real network, the megabytes above arrive first.

Memory

50× smaller footprint

performance.measureUserAgentSpecificMemory() on a cross-origin-isolated page: the one instrument that attributesWebAssembly linear memory to the page, so Blazor's .NET heap is counted, not hidden. Measured after the full interaction burst; median of 5 cold pages; per-run attribution breakdowns kept in the committed JSON.

All the numbers

MeasureBlazor (no JIT)Blazor (AOT)Filament
Wire bytes to interactive (gzip)2.13 MB5.87 MB5.0 KB
Wire bytes to interactive (brotli)1.75 MB4.02 MB4.4 KB
Time to interactive (brotli, median)180 ms233 ms26.9 ms
Time to interactive (IQR)3.59 ms4.79 ms0.97 ms
Memory after load41.47 MB45.16 MB752.7 KB
Memory after interaction burst41.65 MB45.33 MB858.7 KB
Requests to interactive48483

How this was measured