Hacker News AI · 10/21/2026, 10:53:47

NetWasm: C# WebAssembly Output Now Smaller Than Rust

68AI Score
Executive Summary

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.

Wasm footprint landscape with raw and Brotli-11 sizes. NetWasm with precise GC is 47,798 raw and 13,501 compressed bytes; Rust is 53,635 and 16,963; Kotlin/Wasm is 79,293 and 22,655; TinyGo is 93,043 and 26,931. NetWasm and Rust are the matched WASI Preview 2 comparison; Kotlin and TinyGo are contextual Preview 1 references.

ToolchainRaw WasmBrotli 11Comparison role
NetWasm 0.8.0, Compact GC47,798 B13,501 BWASI P2 Component; precise GC included
Rust 1.95.0, size profile53,635 B16,963 BMatched WASI P2 Component reference
Kotlin 2.4.0 wasmWasi79,293 B22,655 BP1 context; GC supplied by the host engine
TinyGo 0.39.093,043 B26,931 BP1 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:

WorkloadNetWasm 0.10.0, NetWasmGCMono AOT, .NET 10NetWasm time
Full transaction43.9 ms59.1 ms26% less
Retained object graph8.8 ms14.2 ms38% less
UI churn17.6 ms29.1 ms40% 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 dotnet CLI;
  • publish C# exports as typed JavaScript modules that run in the page or in a Web Worker;
  • link compatible Wasm .a archives 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.1 and 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:

SH
dotnet new install NetWasm.Templates
dotnet new netwasm-app -n HelloNetWasm
cd HelloNetWasm
dotnet restore
dotnet run
dotnet publish -c Release -o publish/local

Run the published component with a compatible WASI Preview 2 host, such as Wasmtime:

SH
wasmtime run publish/local/HelloNetWasm.wasm
TEXT
42

The 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 dynamic keyword 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)

NetWasm: C# WebAssembly Output Now Smaller Than Rust | Today for AI