How Does WebAssembly (WASM) Work?
Run C++/Rust/Zig Code at Native Speed in the Browser
WebAssembly (WASM) is a bytecode format that runs code written in statically-typed languages like C++, Rust, and Zig at near-native speed in the browser.
Architecture Diagram
- JavaScript cannot compile to WASM — WASM is a compile target for statically typed languages only
- WASM cannot access the DOM directly โ JS wrapper (glue code) acts as a bridge
- Runs inside the browser sandbox โ same security as native apps
- Real examples: Figma(C++), FFmpeg.wasm(C), Ghostty Web(Zig), Photoshop(C++)
How It Works
Write source code (C++, Rust, Zig, or other statically-typed languages)
Generate .wasm bytecode with language-specific compilers (Emscripten, wasm-pack, zig build, etc.)
Write JS/TS wrapper (glue code) โ expose WASM functions as JS API, bridge to Web APIs
Distribute as npm package (e.g., npm install ghostty-web). WASM bundled as base64 inline or separate .wasm file
Frontend build tools (Vite, webpack) bundle the package. Load WASM module via dynamic import()
Browser compiles bytecode via WebAssembly.compile() โ instantiate() to create instance
Call WASM functions from JS โ Call JS callbacks from WASM โ bidirectional communication
Pros
- ✓ Near-native execution speed (10-100x faster computation vs JS)
- ✓ Reuse existing C++/Rust codebases (even 30-year-old C++ code runs on the web)
- ✓ Sandboxed execution (browser security model applies as-is)
- ✓ Language-independent (any language that compiles works)
- ✓ Reduced server load (heavy computation runs on the client)
Cons
- ✗ No direct DOM/Web API access โ must go through JS glue code
- ✗ Complex build environment (Emscripten/wasm-pack setup, cross-compilation)
- ✗ Initial load time (.wasm download + compilation overhead)
- ✗ Difficult debugging (immature source maps, no console.log)
- ✗ Manual memory management (no GC), serialization cost for JSโWASM data exchange