Hacker News AI · 10/21/2026, 10:53:47
NetWasm: C# WebAssembly Output Now Smaller Than Rust
NetWasm v0.8.0 introduces precise garbage collection, enabling C# to compile into WebAssembly binaries that are 10.9% smaller than Rust's size-oriented profile. With Brotli compression, the advantage expands to 20.4%, demonstrating significant footprint reduction for standalone Wasm components.
SOURCE COVERAGEFull Original Report
Contents5 sections
NetWasm
Independent .NET for WebAssembly and WASI.<br> Write C#. Deploy small, standalone Wasm.
NetWasm is an independent compiler, CoreLib, runtime and SDK that compiles C#
and .NET CIL directly to WebAssembly. It does not carry the desktop CLR, Mono,
dotnet.js or application DLLs into production.
Compile C# to WebAssembly · Try it in the browser · Install and build · See supported APIs · Read the documentation
C# now beats Rust on Wasm size
NetWasm 0.8.0 + precise GC: 47,798 bytes<br> Rust 1.95.0 size-oriented profile: 53,635 bytes
For the same print-42 workload, NetWasm's result includes the runtime and
precise Compact garbage collector. Both artifacts are standalone WASI Preview 2
Components built with size-oriented settings.
10.9% smaller raw. 20.4% smaller with Brotli-11.
| Toolchain | Raw Wasm | Brotli 11 | Comparison role |
|---|---|---|---|
| NetWasm 0.8.0, Compact GC | 47,798 B | 13,501 B | WASI P2 Component; precise GC included |
| Rust 1.95.0, size profile | 53,635 B | 16,963 B | Matched WASI P2 Component reference |
Kotlin 2.4.0 wasmWasi | 79,293 B | 22,655 B | P1 context; GC supplied by the host engine |
| TinyGo 0.39.0 | 93,043 B | 26,931 B | P1 context; precise GC configured |
Rust is the headline comparison because it uses the same workload and output form. Kotlin/Wasm and TinyGo show the broader footprint landscape, but their targets and runtime boundaries differ. This is a measured workload/profile result, not a language-wide size ranking.
Exact sources, versions, settings and reproduction steps
Faster than Mono AOT
As of 0.10.0, NetWasm runs our allocation and garbage-collection benchmarks faster than Mono AOT, compiled from the same C# source and run by the same Wasmtime:
| Workload | NetWasm 0.10.0, NetWasmGC | Mono AOT, .NET 10 | NetWasm time |
|---|---|---|---|
| Full transaction | 43.9 ms | 59.1 ms | 26% less |
| Retained object graph | 8.8 ms | 14.2 ms | 38% less |
| UI churn | 17.6 ms | 29.1 ms | 40% less |
These are medians of 15 runs on an Apple M1 Max under Wasmtime 49.0.3, each run
checked against desktop .NET's result. Mono AOT is Microsoft's wasi-wasm
target in its default Release configuration. NetWasmGC also takes less time than
desktop .NET 11's JIT on the first two workloads (49.9 and 9.7 ms); the JIT is
faster on UI churn (8.6 ms), and desktop NativeAOT is the fastest on all three.
Versions, settings, desktop figures and reproduction
More than Hello World
The 46.7 KiB program is the baseline, not the boundary.
C# 15 · JavaScript modules and Web Workers · static .a interop · WIT/WASI P2 ·
expression trees · HTTP/JSON/XML/Regex · reflection-free DI ·
TUnit/VSTest · wasm64 · four allocation strategies
Today NetWasm can:
- build, run, publish and test projects through the ordinary
dotnetCLI; - publish C# exports as typed JavaScript modules that run in the page or in a Web Worker;
- link compatible Wasm
.aarchives and generate bounded C ABI marshalling; - generate C# bindings from WIT and produce standalone WASI P2 Components;
- construct and inspect expression trees without general runtime reflection;
- use independently packaged LINQ, HTTP, JSON, XML, Regex, Hashing and dependency-injection libraries;
- dual-target libraries for
netwasm0.1and desktop .NET.
The profile is deliberately smaller than desktop .NET. It already supports complete applications, portable libraries, test projects and browser modules.
Try it
Install .NET SDK 10.0.303 or newer, then run:
dotnet new install NetWasm.Templates
dotnet new netwasm-app -n HelloNetWasm
cd HelloNetWasm
dotnet restore
dotnet run
dotnet publish -c Release -o publish/localRun the published component with a compatible WASI Preview 2 host, such as Wasmtime:
wasmtime run publish/local/HelloNetWasm.wasm42The published component is self-contained with respect to .NET. A WebAssembly host is still required. Build with .NET; run without .NET.
Projects using C# 15 select the .NET 11 SDK; earlier language versions can stay on .NET 10. The SDK restores its pinned Node, LLD and Binaryen tools through NuGet, so an ordinary app does not require a separate Emscripten, Git or Python installation. See the complete quickstart for host, restore, Windows, browser and dual-targeting details.
How it stays small
Roslyn produces CIL. NetWasm compiles the reachable program directly to Wasm, specializes its generics and links only the runtime support it needs. The linked Wasm component is the program.
- Closed-world compilation. Unreachable code, imports and runtime features do not enter the artifact.
- A smaller platform contract. NetWasm supports portable APIs instead of reproducing every desktop runtime assumption.
- No broad runtime reflection. Runtime type names, dynamic assembly loading
and the
dynamickeyword are outside the profile. - Generated boundaries. JSON, DI, WIT and native interop use known contracts rather than runtime discovery.
- Optional data and diagnostics. Timezone data, rich stack traces and other deployment data are included only when selected.
- One collector. Only the chosen allocation strategy is linked.
This is a new .NET platform, not desktop .NET squeezed into a Wasm sandbox. That boundary is what makes native-Wasm-sized C# possible.
How JSON and optional features affect size
(注:更多技术实现细节与完整 API 文档请查阅原项目 README)