Rust for WebAssembly: How I Built Near-Native Performance Web Apps
Source: Dev.to
Introduction
I wanted real browser performance—not “fast enough” or “optimized JavaScript.”
So I tried Rust + WebAssembly.
The journey included:
- Broken builds
- Missing WASM targets
- Confusing bundler errors
- Lots of “why is this not loading?”
Once everything clicked, it became one of the most powerful tools in my stack.
If you want to use Rust for WebAssembly without drowning in tooling chaos, here’s exactly what worked for me. In this post you’ll go from zero setup to running Rust in the browser—including performance use cases and production patterns.
What We’re Building
Rust + WebAssembly + JavaScript integration → 🚀
Near‑native performance inside the browser → ⚡
We’ll:
- Install the Rust WASM target
- Use
wasm-packproperly - Generate JS bindings
- Integrate with a frontend
- Understand where this actually makes sense
No theory fluff—just practical steps.
Step 1: Install the WebAssembly Target
First mistake: trying to compile without the WASM target.
rustup target add wasm32-unknown-unknown
If this fails, check your Rust version:
rustc --version
Make sure you’re on the stable channel.
Step 2: Install wasm-pack (Critical Tool)
wasm-pack simplifies everything.
cargo install wasm-pack
Without it you’ll struggle generating JavaScript bindings. It handles:
- Compilation
- Glue code
- Packaging
- npm compatibility
Step 3: Create a Rust WASM Project
cargo new rust_wasm_demo --lib
cd rust_wasm_demo
Update Cargo.toml
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2"
This configuration enables WebAssembly bindings.
Step 4: Write Rust That Exports to JavaScript
src/lib.rs:
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
The #[wasm_bindgen] attribute exposes the Rust function to JavaScript. Without it, nothing works.
Step 5: Build for the Browser
wasm-pack build --target web
This generates a pkg/ directory containing:
.wasmbinary- JavaScript bindings
- TypeScript definitions
If you encounter linker errors, double‑check:
- The WASM target is installed
- No Windows MSVC conflicts (see my post on fixing Rust issues on Windows here)
- Crate type is set to
cdylib
Step 6: Use It in the Browser
Create a simple HTML file:
import init, { add } from "./pkg/rust_wasm_demo.js";
async function run() {
await init();
console.log(add(5, 3));
}
run();
Serve the directory with a local server (browsers block WASM loading via file://):
npx serve .
Where Rust + WebAssembly Actually Shines
Don’t rewrite your whole frontend. Use it for:
- Heavy math computations
- Cryptography
- Image processing
- Parsing large datasets
- Blockchain logic
- AI model preprocessing
For simple UI logic, JavaScript is fine.
Production Pattern (What I Actually Use)
Typical setup
Frontend (React / Next.js)
↓
WASM module for heavy compute
↓
Return results back to UI
Example usage:
import init, { add } from "rust_wasm_demo";
await init();
const result = add(10, 20);
Keep WASM isolated to performance‑critical functions.
Common Mistakes
- Trying to use WASM for everything
- Forgetting async initialization (
await init()) - Not serving via HTTP
- Fighting bundlers unnecessarily
- Ignoring bundle size
Remember: WASM is fast, but not magic. It speeds up compute, not DOM manipulation.
Performance Reality Check
Why is Rust fast?
- Compiles to optimized machine‑level bytecode
- Memory is manually controlled
- No runtime overhead like garbage collection
When compiled to WebAssembly, you get near‑native speed inside the browser sandbox.
Final Thoughts
Rust + WebAssembly is not hype; it’s a precision tool. Use it when you:
- Need serious performance
- Want memory safety
- Are building compute‑heavy apps
Use it strategically, not emotionally.
If this helped you break into Rust + WASM without losing your sanity, feel free to share it.
What’s Next?
- Rust WASM inside Next.js
- Using WASM for blockchain clients
- Benchmarking Rust vs. JavaScript properly
Let me know which one you want.
Check me out at .