Conceptly
← All Concepts
βš™οΈ

WebAssembly

ClientA binary execution format that delivers near-native performance in the browser

WebAssembly (WASM) is a binary instruction format designed as a compilation target for the web. Source code written in languages like C, C++, or Rust is compiled into a .wasm binary that the browser JIT-compiles and executes at near-native speed. Unlike JavaScript, which the browser must parse from text, WASM arrives as optimized bytecode that can be compiled directly, enabling predictable high performance for CPU-intensive workloads in the browser.

β–ΆArchitecture Diagram

πŸ”„ Process

Dashed line animations indicate the flow direction of data or requests

Why do you need it?

Running heavy computations in the browser has long been a structure where JavaScript alone had to handle everything. Every time someone tried to encode video in real time, run a physics simulation, or bring a CAD tool to the web, they hit the performance ceiling imposed by JS's single-threaded execution and dynamic type system. Using proven libraries written in C++ or Rust on the web meant either rewriting them in JS or giving up, and either path incurred both development cost and performance loss.

Why did this approach emerge?

The early web was a space for displaying documents, but as web apps increasingly took on the roles of native apps, performance demands rose sharply. asm.js appeared in 2013 as an attempt to speed things up by using a subset of JS as optimization hints, but parsing costs were large and optimization guarantees were insufficient. WebAssembly, co-designed by Mozilla, Google, Microsoft, and Apple, shipped simultaneously in all major browsers in 2017. Instead of parsing text like JS, it created a structure where already-optimized bytecode could be JIT-compiled directly, enabling predictable performance even inside the browser.

How does it work inside?

WebAssembly's execution path starts from source code and is completed offline when a compiler produces a .wasm binary. C/C++ code is converted to WASM bytecode by toolchains like Emscripten; Rust code uses wasm-pack. The browser receives this .wasm file and JIT-compiles it into a form close to native code for execution. The connection to JS is made through the WebAssembly JavaScript API. Loading a module with WebAssembly.instantiate() allows JS to call WASM functions directly. Data exchange works by writing values to WASM linear memory (an ArrayBuffer) and reading them from JS. Since WASM itself cannot access the DOM or make network calls directly, UI manipulation and external communication are always handled by JS.

Boundaries & Distinctions

WebAssembly and JavaScript are not substitutes for each other. WASM handles CPU-intensive tasks where JS is slow -- numerical computation, cryptography, media processing -- while JS handles the parts that interface with the browser ecosystem: DOM manipulation, event handling, network calls. In practice, no web app runs on WASM alone; JS always serves as the glue. The relationship with Web Workers is also important. Running WASM computations on the main thread blocks UI rendering, so the common pattern is to run heavy WASM work inside a Web Worker. The Worker provides computation isolation and threading; WASM provides performance within it. With SharedArrayBuffer, the Worker and main thread can share WASM memory directly, but this requires Cross-Origin-Isolation headers for defense against side-channel attacks like Spectre. The actual cost at the JS-WASM boundary comes from type conversion. WASM directly handles only types like i32, i64, f32, and f64, so passing strings or structs requires serializing them as bytes into linear memory. The higher the call frequency, the more this serialization cost accumulates, making it advantageous to reduce the number of WASM function calls and batch work into fewer, larger calls.

When should you use it?

WASM is meaningfully impactful where the limits of JS performance directly affect user experience. Representative cases include browser-based video editing tools where encoding time drops from tens of seconds to a few seconds, 3D modeling apps where rendering frames stay stable, and complex spreadsheets where millions of rows compute without stuttering. The ability to reuse existing C/Rust libraries is also important in practice. Examples include compiling SQLite to WASM for use as an in-browser offline database, and porting audio codecs, PDF renderers, and cryptography libraries without rewriting them in JS. However, moving all code to WASM is not recommended. In patterns where DOM manipulation is heavy or JS and WASM calls alternate in short bursts, serialization overhead can actually make things slower. WASM works best when focused on computations where JS is the bottleneck, with everything else remaining in JS.

Game engine porting -- running game logic written in C++ in the browser at near-original speedVideo and image processing -- executing codec, filter, and transformation algorithms far faster than JSCAD and scientific simulation -- offloading complex numerical computations to the clientReusing existing C/Rust libraries -- using proven native libraries directly on the web