Skip to content

Why Wasm? Where Does It Run?

WebAssembly did not appear by accident. It was designed to solve a specific cluster of problems that JavaScript alone cannot address. Understanding why Wasm exists — and where it runs — gives you the mental model you need to decide when to reach for it.

Wasm is compiled to a compact binary before it ever reaches the runtime. The engine does not parse source text, tokenize, or build an AST at load time. AOT or JIT compilation from the binary format is fast and produces near-native machine code. For compute-intensive work — image processing, audio codecs, cryptography, physics simulations — this gap is measurable and significant.

A single .wasm binary runs identically everywhere: x86-64 laptops, ARM phones, RISC-V embedded boards, browsers, edge nodes. There is no recompilation step for each target architecture. The runtime validates and executes the binary against a well-specified instruction set.

Wasm is a compilation target, not a language you write by hand in production. This means you choose the right tool for the job:

  • Rust — zero-cost abstractions, no garbage collector, excellent wasm-pack toolchain
  • C / C++ — decades of existing native libraries, compiled with Emscripten
  • Go — good standard library support, growing ecosystem
  • AssemblyScript — TypeScript-like syntax that compiles directly to Wasm
  • Python — via Pyodide, a full CPython compiled to Wasm running in the browser

Wasm runs inside a strict sandbox. The module cannot access the host’s memory, file system, or network unless the host explicitly provides those capabilities as imports. Linear memory is bounds-checked on every access. There are no ambient permissions — a Wasm module starts with nothing and is granted only what it needs.

The primary home of Wasm is the browser, via the WebAssembly JavaScript API. A page loads a .wasm binary, instantiates it with WebAssembly.instantiate, and calls its exported functions directly from JavaScript.

const response = await fetch('module.wasm');
const bytes = await response.arrayBuffer();
const { instance } = await WebAssembly.instantiate(bytes, {});
instance.exports.myFunction();

All major browsers — Chrome, Firefox, Safari, Edge — have shipped full Wasm support since 2017.

Node.js exposes the same WebAssembly.* API as the browser. Deno and Bun do the same. Cloudflare Workers and Fastly Compute support Wasm modules natively, which means you can deploy the identical binary to the browser and the edge without any changes.

The WebAssembly System Interface (WASI) is a standardised ABI that lets Wasm code run outside the browser with controlled access to OS capabilities — files, sockets, clocks, random — without any JavaScript host at all. Runtimes like wasmtime and wasmer implement WASI, letting you execute a .wasm binary as a standalone process.

Wasm’s sandboxing makes it ideal for plugin architectures. Tools like Extism and embedded wasmtime let applications load untrusted Wasm plugins, expose a controlled API surface, and enforce strict memory and capability limits — all without spinning up a separate process.

Wasm does not replace JavaScript. The DOM, event handling, fetch, and most web platform APIs are only accessible from JavaScript. The practical pattern is a division of labour: keep IO, events, and DOM manipulation in JavaScript, and hand CPU-heavy algorithms to a Wasm module.

Which of these is NOT a primary reason to use WebAssembly?
WASI stands for...
Which statement best describes Wasm and JavaScript in the browser?