NET CIL to small standalone Wasm with WASI (AOT with built-in Runtime and Precise GC)
The project's README from github.com/zion-sati/NetWasm. As one markdown file: README.md.
Independent .NET for WebAssembly and WASI.
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
NetWasm 0.8.0 + precise GC: 47,798 bytes
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
The 46.7 KiB program is the baseline, not the boundary.
C# 15 · 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:
dotnet CLI;.a archives and
generate bounded C ABI marshalling;netwasm0.1 and desktop .NET.The profile is deliberately smaller than desktop .NET. It already supports complete applications, portable libraries, test projects and browser workers.
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/local
Run the published component with a compatible WASI Preview 2 host, such as Wasmtime:
wasmtime run publish/local/HelloNetWasm.wasm
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.
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.
dynamic keyword are outside the profile.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
Compact is the default: a size-first, precise, non-moving mark-and-sweep collector. It traces compiler-published roots and reference layouts without conservative scanning. Its name refers to implementation size, not moving heap compaction.
| Strategy | Best fit | Raw component | Brotli 11 |
|---|---|---|---|
| Compact (default) | Small applications and low-churn UI | 47,798 B | 13,501 B |
| NetWasmGC | Higher allocation throughput | 51,300 B | 15,157 B |
| Bump | Bounded, one-shot jobs | 43,794 B | 11,929 B |
| Boehm | Conservative collector compatibility | 74,142 B | 25,023 B |
Select a strategy in the executable project's .csproj:
<PropertyGroup>
<NetWasmGarbageCollector>NetWasm</NetWasmGarbageCollector>
</PropertyGroup>
Leaving the property unset selects Compact. Libraries remain collector-neutral; all four backends are packaged for wasm32 and wasm64. See Choosing a garbage collector for the tradeoffs and diagnostics.
A library written for the smaller NetWasm profile should also be useful on desktop .NET, rather than trapped in a Wasm-only ecosystem.
dotnet new netwasm-lib -n MyLibrary
The template targets netwasm0.1 and net10.0, producing NuGet assets for
both platforms. This is explicit multi-targeting, not a promise that arbitrary
desktop packages work in reverse.
NetWasm.Libraries provides the
ported framework and extensions packages.
TUnit-NetWasm provides ordinary
dotnet test integration through the generic VSTest bridge.
For an empty-UI Blazor WebAssembly application that prints 42, with AOT,
managed trimming, IL stripping, invariant globalization and size-focused native
linking enabled:
| AOT build | Uncompressed Wasm | Relative to NetWasm |
|---|---|---|
| NetWasm 0.8.0, Compact GC | 47,798 B | 1× |
| Blazor WebAssembly, .NET 10 | 12,276,684 B | 257× |
| Blazor WebAssembly, .NET 11 RC1 | 15,289,241 B | 320× |
The Blazor total includes its native runtime and required Webcil assemblies; NetWasm includes its runtime, garbage collector and WASI component. This is a console component versus an empty-UI application—not an equivalent-framework comparison or a claim about every .NET workload.
Exact Blazor versions, settings and reproduction
NetWasm is pre-1.0. Its supported profile is usable today and covered by published qualification, but source, package, target-profile and ABI contracts may change between minor releases.
The normal portable output is a wasm32 WASI Preview 2 Component. Raw wasm32, raw wasm64 and JavaScript-host integration are advanced alternatives; wasm64 Components remain blocked by upstream tooling.
Runtime reflection, dynamic, runtime assembly loading and managed threading
are outside the profile. General System.IO.File/Directory/FileStream, raw
sockets and subprocess APIs are not yet implemented. Existing NuGet packages
work only when their reachable code and API dependencies fit the supported
profile.
Supported APIs and limitations · Documentation index
NetWasm 1.0 means a useful, documented and stable smaller platform. It does not mean “desktop .NET, but in Wasm.” The main remaining themes are:
netwasm1.0 platform and runtime contract;Coming in NetWasm 0.9.0: broader compatibility with existing .NET Standard 2.1 library binaries and NuGet assets. The target is to consume libraries unchanged when their reachable code fits the NetWasm profile, without carrying unused unsupported paths into the application.
This does not turn NetWasm into desktop .NET. Reachable general runtime
reflection, dynamic, runtime assembly loading, managed threading, unsupported
host APIs and named-culture globalization remain outside the initial 0.9.0
compatibility slice and fail at compile time.
NetWasm.Compiler.Browser · NetWasm.Compiler.Tasks · NetWasm.Hosting · NetWasm.Hosting.Build · NetWasm.Ref · NetWasm.Runtime.Pack · NetWasm.Runtime.Wasm32 · NetWasm.Runtime.Wasm64 · NetWasm.Sdk · NetWasm.Templates · NetWasm.Testing.VSTest · NetWasm.Toolchain · NetWasm.Wit.Bindings.Tool
CoreLib, runtime libraries, templates and generated support code are MIT, subject to preserved upstream notices. The compiler and developer tooling use the NetWasm Community License 1.0. The Compact collector retains its Apache-2.0 license and AssemblyScript attribution.
The Community License is free for qualifying individuals, education, open-source work, evaluation, and organizations with fewer than 250 employees and less than USD 10,000,000 in annual revenue. Matching GitHub Sponsors tiers grant limited internal commercial use; OEM and Commercial Offering use require a separate agreement. Generated applications may use their authors' chosen licenses. There is no sign-in, activation, telemetry or technical enforcement.
Licensing guide · Third-party notices · Commercial licensing: [email protected]
Start with Console.WriteLine(42), then try the smallest real workload where
deployment size, sandboxing or portability matters. If something is missing,
open an issue. Concrete workloads
are how the 1.0 support boundary gets decided.
NET CIL to small standalone Wasm with WASI (AOT with built-in Runtime and Precise GC)