WebAssembly Best Practices
Rules for WASM modules with clear interop boundaries and minimal payload size.
Search across all documentation pages
Rules for WASM modules with clear interop boundaries and minimal payload size.
Vec<u8> / String over long-lived borrows.Result<JsValue, JsValue> in browsers; integer codes in WASI.console_error_panic_hook in dev only.opt-level = "s", LTO, panic = "abort".default-features = false where possible.application/wasm with compression.eval; use module imports.wasm-bindgen, wasm-pack, and Rust channel in CI.wasm32-unknown-unknown vs wasm32-wasi vs components.CPU-heavy, portable logic: parsers, crypto, simulations, image/audio codecs.
Keep auxiliary modules under ~100 KB gzipped; split larger apps into lazy chunks.
Few coarse-grained exports beat dozens of tiny functions called in tight loops.
Unit test logic on native target; wasm-bindgen-test for browser-specific code.
Growing for edge and plugins. Confirm runtime support before betting the architecture.
Adopt for new polyglot plugin boundaries; keep wasm-bindgen for existing browser apps.
Browser tabs cap WASM memory. Stream large data instead of loading entirely into linear memory.
Structured logging to host console; source maps in staging only.
Semver npm package; breaking export changes bump major version.
If UI is WASM-rendered, manage focus and ARIA like any SPA framework.
Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.
Reviewed by Chris St. John·Last updated Jul 16, 2026