The Ecosystem: Languages, Tools, and Real Uses

This chapter surveys other source languages (C/C++, Go, AssemblyScript, Zig), key tooling (wabt, wasm-opt), and how major products actually use Wasm.

Languages That Target Wasm

Rust is the most Wasm-idiomatic language, but far from the only one.

C and C++ via Emscripten

Emscripten is a full LLVM-based toolchain that compiles C and C++ to Wasm (or to asm.js, historically). It's been around since before Wasm itself and is how most large legacy codebases get to the browser.

emcc main.c -o out.html -s WASM=1

Emscripten generates JS glue, HTML shells, and the .wasm. It simulates a POSIX-ish environment (stdio, filesystem, even threads) via JS.

Real use: Adobe Photoshop on the web (C++ via Emscripten), Google Earth, AutoCAD Web.

Go via TinyGo

The standard Go compiler can target Wasm (GOOS=js GOARCH=wasm), but the output is large (2+ MB for a hello world) because it embeds the whole Go runtime including its garbage collector.

TinyGo is a smaller alternative, optimized for embedded and Wasm targets:

tinygo build -o out.wasm -target wasm main.go

TinyGo's output is kilobytes, not megabytes. Supports a subset of the Go standard library; most common packages work, some don't.

AssemblyScript

A TypeScript-like language that compiles directly to Wasm. Aimed at web developers who want Wasm performance without learning Rust or C.

export function add(a: i32, b: i32): i32 {
    return a + b;
}
asc assembly/index.ts --target release

AssemblyScript is less popular than Rust for new projects, but still ships in production: Shopify tried it, some ML inference libraries use it, and its syntax is a gentle on-ramp.

Zig

Zig's Wasm output is tiny. The language's "no hidden allocation" philosophy fits Wasm's constrained environment well.

export fn add(a: i32, b: i32) i32 {
    return a + b;
}
zig build-lib main.zig -target wasm32-freestanding -dynamic -rdynamic

Zig is a good choice if you want near-Rust-level control with less syntactic ceremony and no macro layer.

.NET via Blazor WebAssembly

.NET runs on Wasm via Mono compiled to Wasm, with ahead-of-time compilation options. Blazor WebAssembly lets you build a frontend app in C# that runs entirely in the browser.

Binary sizes are large (10+ MB typical). Ahead-of-time and trimming bring it down. Nice fit if your team is .NET-first.

Others

Java (TeaVM, CheerpJ), Python (Pyodide), Ruby (ruby.wasm), Kotlin (Kotlin/Wasm), Swift (experimental), Haskell (Asterius): they all exist. Bundle size and feature completeness vary.

Picking a Source Language

  • New project, performance-critical: Rust.
  • Existing C/C++ codebase: Emscripten.
  • Existing Go service: TinyGo.
  • Tiny output, minimal deps: Zig or AssemblyScript.
  • Already a .NET shop: Blazor.

The source language choice doesn't affect where the Wasm runs; it affects developer experience, bundle size, and ecosystem.

Essential Tooling

Four tools that pay for themselves the first week.

wabt (WebAssembly Binary Toolkit)

A suite of utilities for working with Wasm files.

wasm2wat  foo.wasm              # disassemble to text
wat2wasm  foo.wat               # assemble from text
wasm-objdump -d foo.wasm        # disassembler-style view
wasm-validate foo.wasm          # validate
wasm-strip foo.wasm             # remove custom sections (names, debug info)

Install:

brew install wabt

wasm-opt (from binaryen)

The optimizer. Shrinks and speeds up Wasm modules.

wasm-opt -Oz  in.wasm -o out.wasm    # optimize for size
wasm-opt -O3  in.wasm -o out.wasm    # optimize for speed
wasm-opt -O4  in.wasm -o out.wasm    # aggressive speed

Always run wasm-opt on release builds. It typically shaves 10 to 30% of size and can double speed on unoptimized code.

twiggy

Profiler for Wasm binary size. "Where are the bytes going?"

twiggy top out.wasm
twiggy top out.wasm -n 20
twiggy dominators out.wasm

Tells you which functions are largest. Great for targeted trimming.

wasm-tools

The Swiss Army knife for Wasm and the Component Model.

wasm-tools print foo.wasm         # to WAT
wasm-tools validate foo.wasm
wasm-tools component new          # wrap a core module as a component
wasm-tools compose ...            # link components together

Use when working with the Component Model (Chapter 10).

Real-World Uses

Where Wasm actually ships, as of early 2026.

Figma

Figma's rendering engine is C++ compiled to Wasm. It's the reason Figma renders complex designs at 60fps in a browser tab. When Figma launched, Wasm was brand new; the bet paid off.

Photoshop on the Web

Adobe ported the C++ Photoshop codebase to the browser via Emscripten. Millions of lines of C++ run in Wasm. Bandwidth and cold start are still challenges, but the feature coverage is extensive.

Shopify Functions

Merchants write Rust, compile to Wasm, upload to Shopify. Shopify runs the Wasm in a sandboxed runtime for every checkout, applying custom discount logic, shipping rates, and delivery customizations at scale.

Cloudflare Workers and Fastly Compute@Edge

Edge compute platforms where Wasm is a first-class runtime alongside V8 isolates. Cold-start times of a few milliseconds make Wasm attractive for per-request code.

Envoy and Istio Wasm Filters

Envoy (the proxy) supports Wasm filters. You write a filter in Rust, compile to Wasm, load into Envoy at runtime without recompiling. Istio's extension mechanism uses this.

Postgres Extensions

Some teams run Postgres extensions in Wasm instead of native .so files, for safer distribution and tenant isolation in managed-Postgres offerings.

Browser ML Inference

ONNX Runtime Web, TensorFlow.js, and ML libraries use Wasm SIMD for fast inference in the browser. Running small-to-medium models client-side keeps latency low and data private.

Plugin Systems (Dapr, SingleStore, Suborbital)

"Run user-supplied code in a sandbox" is a common server-side need. Dapr, SingleStore, and others use Wasm as their plugin runtime.

Patterns Across Uses

Across all these examples:

  • Wasm isn't the whole application; it's a CPU-bound core inside a JS or native host.
  • The boundary is carefully designed: minimal crossings, typed interfaces.
  • Sandboxing (for untrusted code) or portability (for existing C++) is the main motivation.
  • Performance matters but so does distribution: "one binary, many targets" is often the pitch.

Community

Wasm moves fast. Useful communities and news:

  • Bytecode Alliance (bytecodealliance.org): stewards of Wasmtime, Cranelift, WASI.
  • WebAssembly Weekly newsletter (webassemblyweekly.com): weekly roundup.
  • r/WebAssembly and Hacker News Wasm threads.
  • CNCF TAG Runtime: where CNCF projects intersect with Wasm (WasmEdge, Spin, others).

Common Pitfalls

Picking the wrong source language. The costs (bundle size, feature availability, debugging) are bigger than you think. Try the hello-world in each candidate before committing.

Skipping wasm-opt. Leaves a lot of bytes and cycles on the table.

Not profiling with twiggy. Your Wasm is bigger than it needs to be; you just don't know which function.

Following the hype cycle. Wasm is not a replacement for JS, for containers, or for processes. It's a particular tool for particular jobs. Use it where it fits.

Next Steps

Continue to 12-best-practices.md for the habits that keep Wasm modules healthy.