Introduction
wasm-bindgen is a Rust library and CLI tool that bridges the gap between WebAssembly and JavaScript. Raw WASM only supports numeric types; wasm-bindgen generates glue code that translates rich types (strings, structs, closures, Promises) between the two worlds. It is the foundation of the Rust WASM ecosystem, used by frameworks like Yew, Leptos, and Dioxus.
What wasm-bindgen Does
- Generates JavaScript binding code for Rust functions exported to WASM modules
- Converts complex types (String, Vec, structs, enums) between Rust and JS automatically
- Provides access to Web APIs (DOM, fetch, console, Canvas) from Rust via the web-sys crate
- Supports async/await by converting Rust Futures into JavaScript Promises
- Enables importing JavaScript functions and classes into Rust code with type safety
Architecture Overview
wasm-bindgen works through a procedural macro (#[wasm_bindgen]) that annotates Rust functions and types. At compile time, it emits metadata into custom WASM sections. The wasm-bindgen CLI post-processes the compiled .wasm file, reads these sections, and generates companion .js glue code that handles argument marshaling, memory allocation, and garbage collection integration. The result is a clean ES module API.
Self-Hosting & Configuration
- Add wasm-bindgen as a dependency in Cargo.toml and annotate exports with #[wasm_bindgen]
- Use wasm-pack (recommended) which automates building, binding generation, and npm packaging
- Configure the target: web (ES modules), bundler (webpack/vite), nodejs, or no-modules
- Import browser APIs via the web-sys and js-sys crates for DOM manipulation and JS interop
- Use wasm-bindgen-test for running Rust unit tests inside a headless browser environment
Key Features
- Zero-overhead bindings that compile to minimal JS glue with no runtime framework
- Support for passing closures from Rust to JS callbacks (event handlers, promises)
- Automatic TypeScript .d.ts generation for type-safe consumption in TS projects
- Integration with web-sys providing bindings to every Web API (2000+ interfaces)
- wasm-bindgen-futures bridges Rust async functions with JavaScript Promise chains
Comparison with Similar Tools
- wasm-pack — Build tool that wraps wasm-bindgen; wasm-bindgen is the underlying binding generator
- Emscripten — C/C++ to WASM compiler with its own runtime; wasm-bindgen is lighter and Rust-native
- AssemblyScript — TypeScript-like WASM language; wasm-bindgen lets you use full Rust with WASM
- wasm-bindgen vs raw WASM — Raw WASM only passes numbers; wasm-bindgen adds strings, objects, and async
- Serde-wasm-bindgen — Serialization bridge; standard wasm-bindgen handles simpler conversions natively
FAQ
Q: Does wasm-bindgen add runtime overhead? A: The generated glue is minimal — it handles type conversion and memory allocation. For numeric types, there is zero overhead. String and object conversions involve copying but are optimized.
Q: Can I use wasm-bindgen without wasm-pack? A: Yes. You can call the wasm-bindgen CLI directly on compiled .wasm files. wasm-pack is a convenience wrapper that handles the full build pipeline.
Q: How does memory management work across the Rust/JS boundary? A: Rust owns its linear memory. When passing strings or arrays to JS, data is copied into JS-managed memory. The generated glue handles freeing Rust allocations when JS wrappers are garbage collected.
Q: Can I call DOM APIs from Rust? A: Yes, via the web-sys crate which provides Rust bindings to all Web IDL interfaces. You can create elements, add event listeners, draw on canvas, and call fetch — all from Rust.