Compile F# to WebAssembly GC — natively, without JavaScript.
A standalone WasmGC backend for the Fable F# compiler. Produces
.wasmbinaries that run on any WasmGC-capable runtime — browsers, Node.js, Wasmtime, WasmEdge.
fsharp-wasm compiles F# source code directly to WebAssembly with garbage collection (WasmGC). No JavaScript glue code, no Emscripten, no linear memory GC — just native Wasm structs and arrays managed by the host runtime's GC.
// hello.fs
module Hello
let fibonacci n =
let mutable a, b = 0, 1
for _ in 1..n do
let t = a + b
a <- b
b <- t
a
let isPrime n =
if n < 2 then false
else
let mutable i = 2
let mutable result = true
while i * i <= n && result do
if n % i = 0 then result <- false
i <- i + 1
resultCompile and run:
dotnet fable hello.fsproj --lang wasmgc
# → output/hello.wasm + output/hello.wat| Category | Features |
|---|---|
| Core Language | Let bindings, recursion, tail calls (return_call), mutual recursion |
| Type System | Records, discriminated unions, pattern matching, generics (monomorphized) |
| Functions | Closures, higher-order functions, currying, partial application |
| Collections | List<'T>, Array<'T>, Option<'T>, Result<'T,'E> with full combinators |
| Strings | Native UTF-16 on GC heap, 35+ operations (concat, split, join, format, trim, etc.) |
| Math | Full System.Math (sin, cos, sqrt, abs, pow, min, max, etc.) |
| Formatting | sprintf, printfn, $"interpolation" |
| Parsing | Int32.Parse, Double.Parse, float cast |
| Multi-file | Multiple .fs files compiled into a single Wasm module |
| FFI | [<Import("name","module")>] for importing host/Wasm functions |
| Component Model | WIT file generation, wasm-tools component embed/new integration |
| Module Linking | Multiple F# compilation units composed at runtime |
| Binary Output | Direct .wasm binary encoding (LEB128, all sections) + human-readable .wat |
| Feature | Status |
|---|---|
Generic Map<'K,'V> / Set<'T> |
Integer keys only; generic dispatch planned |
| Interface dispatch / vtables | Design complete, implementation upcoming |
seq { } / IEnumerable |
Planned |
| Typed exceptions | Basic try/with works; typed throws planned |
| Async / JSPI | Planned |
- .NET SDK 10.0+ (see
global.json) - Node.js 22+ (for running tests)
wasm-tools(optional, for binary validation and Component Model)
git clone --recursive https://github.com/fsharp-wasm/fsharp-wasm.git
cd fsharp-wasmIf you already cloned without --recursive:
git submodule update --init --recursivedotnet build src/Fable.WasmGc.fsprojThis builds:
- The WasmGC backend (
Fable.WasmGc.fsproj) - All required Fable projects from the vendored submodule (
Fable.Compiler,Fable.Cli, etc.)
# Unit tests (353 tests)
cd tests/QuickTest && bash run.sh
# Showcase (26 real-world algorithms)
cd tests/Showcase && bash run.sh
# Component model examples
cd examples/component-embed && bash run.sh # 39 tests
cd examples/component-linking && bash run.sh # 22 testsNote: The test scripts run the compiler via
dotnet run --project vendor/Fable/src/Fable.Cliwhich automatically resolves the WasmGC backend from the parent repo.
Pushing a v* tag runs .github/workflows/release.yml and publishes GitHub Release assets for:
- the platform-specific
Fable.Clicompiler archives - a
Fable.WasmGc-net10.0.zipbuild of the backend DLLs - a
Fable.WasmGcNuGet package (.nupkg)
NuGet upload is wired into the release workflow and stays skipped until the NUGET_API_KEY secret is configured.
-
Create an F# project:
dotnet new console -lang F# -n MyApp
-
Compile to WasmGC:
dotnet fable MyApp.fsproj --lang wasmgc
-
Run with Node.js:
const { readFileSync } = await import("fs"); const bytes = readFileSync("output/MyApp.wasm"); const { instance } = await WebAssembly.instantiate(bytes); console.log(instance.exports.myFunction(42));
F# Source (.fs)
│
▼
┌──────────────────────┐
│ F# Compiler Service │ Parse + type-check
│ (via Fable 5) │
└──────────┬───────────┘
│ Fable AST
▼
┌──────────────────────┐
│ Fable2WasmGc │ F# AST → WasmGC IR
│ + Replacements │ BCL inlining (List, Array, Option, Math, String...)
│ + Monomorphization │ Generic specialization
└──────────┬───────────┘
│ WExpr / WModule
▼
┌──────────────────────┐
│ Optimize │ Constant folding, dead code elimination
└──────────┬───────────┘
│
┌─────┴─────┐
▼ ▼
┌─────────┐ ┌──────────┐
│ WAT │ │ Encoder │ .wat (text) + .wasm (binary)
│ Emitter │ │ (Binary) │
└─────────┘ └──────────┘
See docs/architecture.md for details.
src/
├── WasmGc.AST.fs # WasmGC IR types (WType, WExpr, WConst)
├── WasmGcPipeline.fs # Pipeline entry point + WIT generation
├── Runtime/ # Runtime helpers, CE builder, type system
├── Transforms/ # Fable AST → WasmGC IR translation
└── Emit/ # WAT emitter, binary encoder, optimizer
fable-library-wasmgc/ # Minimal F# standard library for WasmGC
tests/ # QuickTest (353) + Showcase (26) suites
examples/ # Component model demos
docs/ # Documentation
vendor/Fable/ # Fable 5 with WasmGC patches
- Getting Started — Setup, build, and first project
- Architecture — Compiler pipeline and design decisions
- WasmGC Backend — How F# maps to WasmGC
- Type Mapping — F# types → Wasm GC types
- Status — Current feature matrix
- Roadmap — What's next
- Contributing — How to contribute
- FAQ — Frequently asked questions
fsharp-wasm leverages Fable's frontend (F# Compiler Service + Fable's typed AST) and adds a completely new backend that targets WebAssembly GC:
- Records → WasmGC
structtypes with named fields - Discriminated Unions → Struct hierarchy with tag dispatch via
br_on_cast - Closures →
$AnyFnbase struct with captured variables +call_refdispatch - Strings → GC-managed
(array i32)with 35+ runtime operations - Lists → Linked-list struct hierarchy (
$ListBase/$ListCons) - Generics → Demand-driven monomorphization (specialized at each call site)
- Tail calls → Native
return_call(zero-cost, handles mutual recursion)
fsharp-wasm is developed as an open-source project. If you find it useful or want to support the development of F# on WebAssembly, please consider sponsoring:
Sponsorship funds go directly toward:
- Full-time development of the compiler backend
- WasmGC specification compliance testing
- Building a complete F# standard library for WebAssembly
- Documentation and ecosystem tooling
MIT — Copyright (c) 2025–2026 Fable WasmGC Backend Contributors
- Fable — The F# to JavaScript/Python/Rust/Dart compiler that provides our frontend
- Bytecode Alliance — For
wasm-toolsand the Component Model - WebAssembly Community Group — For the WasmGC specification