Rust and wasm-bindgen
Rust is the most popular language for writing new WebAssembly modules. Its zero-cost abstractions, no garbage collector, and excellent tooling make it a natural fit. The wasm-bindgen crate generates the JavaScript glue code automatically, and wasm-pack wraps the whole build pipeline into a single command.
Install the toolchain
Section titled “Install the toolchain”# Install Rust (if not already installed)curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Add the WebAssembly target to the Rust toolchainrustup target add wasm32-unknown-unknown
# Install wasm-pack — the all-in-one Rust → Wasm build toolcargo install wasm-packCreate a new project
Section titled “Create a new project”# Create a library crate (not a binary)cargo new --lib hello-wasmcd hello-wasmAdd wasm-bindgen to Cargo.toml:
[lib]crate-type = ["cdylib"]
[dependencies]wasm-bindgen = "0.2"Write the Rust function
Section titled “Write the Rust function”Open src/lib.rs and write a simple exported function:
use wasm_bindgen::prelude::*;
/// Returns a greeting string.#[wasm_bindgen]pub fn greet(name: &str) -> String { format!("Hello, {}! from WebAssembly", name)}
/// Adds two 32-bit integers.#[wasm_bindgen]pub fn add(a: i32, b: i32) -> i32 { a + b}The #[wasm_bindgen] attribute tells the code generator to create matching JavaScript bindings. Without it, the function is compiled into the .wasm binary but is not accessible from JS.
Build with wasm-pack
Section titled “Build with wasm-pack”# Build for use in a bundler (webpack, Vite, Rollup)wasm-pack build --target bundler
# Build for direct use in a browser via <script type="module">wasm-pack build --target web
# Build for Node.jswasm-pack build --target nodejsThe pkg/ directory is created with:
pkg/ hello_wasm_bg.wasm ← the compiled Wasm binary hello_wasm.js ← generated JS glue hello_wasm.d.ts ← TypeScript types package.json ← ready to publish on npmCall from JavaScript
Section titled “Call from JavaScript”// When using --target web (no bundler required)import init, { greet, add } from './pkg/hello_wasm.js';
async function main() { // init() downloads and instantiates the .wasm file await init();
console.log(greet('world')); // Hello, world! from WebAssembly console.log(add(3, 4)); // 7}
main();When using a bundler such as Vite, the import is identical but init() is handled automatically:
// Vite / webpack — bundler handles instantiationimport { greet, add } from 'hello-wasm';
console.log(greet('WebAssembly'));Passing complex types
Section titled “Passing complex types”wasm-bindgen handles more than just numbers. You can pass:
&str/String— UTF-8 strings are copied through a shared memory bufferJsValue— an opaque handle to any JavaScript valueVec<u8>— byte arrays mapped toUint8Array
use wasm_bindgen::prelude::*;
#[wasm_bindgen]pub fn reverse_string(s: &str) -> String { s.chars().rev().collect()}