Skip to content

Expert · Real projects: CLI, web and WebAssembly · topic 46 of 50 · 30 min

Rust and WebAssembly

Explanation

WebAssembly (Wasm) is a compact binary format that browsers run at near-native speed next to JavaScript. Rust compiles to it with the wasm32-unknown-unknown target. wasm-bindgen generates the glue so JavaScript can call your #[wasm_bindgen] functions, and wasm-pack is a common helper that builds a ready-to-import package. Use it for heavy computation in the browser, not for ordinary page logic.

What is WebAssembly?

Browsers originally ran only JavaScript. WebAssembly, supported by all major browsers since 2017, is a second language for the web: a compact, binary instruction format that runs in the same safe sandbox as JavaScript, but much closer to native machine speed for heavy calculations. You do not write Wasm by hand; you compile another language, such as Rust, C++ or Go, to it.

Think of it like this: Think of a web page as an office. JavaScript is the friendly receptionist who handles visitors, forms and buttons. WebAssembly is a specialist in the back room who does the heavy number work (resizing photos, compressing PDFs) very fast. The receptionist passes the job to the specialist and takes the result back to the visitor.

When Rust + Wasm makes sense

  • Image and video processing in the browser: filters, resizing, background blur.
  • PDF, spreadsheet or file-format work done on the user's device, so files never leave it (good for privacy).
  • Games, simulations, charts with huge data sets.
  • Sharing one tested Rust library between a server and a web front end.

It is not a good fit for ordinary button clicks and form handling: JavaScript is already fast enough there, and crossing between JS and Wasm has a small cost. Wasm also cannot touch the page (the DOM) directly; it goes through JavaScript glue.

The toolchain

bash
rustup target add wasm32-unknown-unknown
cargo install wasm-pack
The target lets rustc produce Wasm. wasm-pack is a build helper; tooling changes over time, so check the current wasm-bindgen docs.
ini
[package]
name = "emi_calc"
version = "0.1.0"
edition = "2024"

[lib]
crate-type = ["cdylib"]

[dependencies]
wasm-bindgen = "0.2"
cdylib produces a library that other languages (here, JavaScript) can load.
rust
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn emi(principal: f64, yearly_rate: f64, months: u32) -> f64 {
    if yearly_rate == 0.0 {
        return principal / months as f64;
    }
    let r = yearly_rate / 12.0 / 100.0;
    let f = (1.0 + r).powi(months as i32);
    principal * r * f / (f - 1.0)
}
#[wasm_bindgen] exports the function to JavaScript and converts simple types (numbers, strings, bools) for you.
bash
wasm-pack build --target web
Produces a pkg/ folder with the .wasm file and a JavaScript wrapper.
html
<script type="module">
  import init, { emi } from './pkg/emi_calc.js';
  await init();                          // load and start the Wasm module
  console.log(emi(500000, 9, 60).toFixed(2));   // 10379.18
</script>
Serve the folder with any local web server; browsers will not load modules from file:// URLs.

Size and debugging tips

  • Build in release mode (wasm-pack does by default) and avoid heavy dependencies; every crate adds bytes users must download.
  • Pass big data as bytes (Vec<u8> / Uint8Array) in one call, rather than calling back and forth thousands of times.
  • Add the console_error_panic_hook crate during development so Rust panics show readable messages in the browser console.

Wasm outside the browser

Wasm also runs outside browsers, in runtimes such as Wasmtime and in some edge-computing and plugin platforms. WASI (the WebAssembly System Interface) gives such programs controlled access to files, clocks and networks. Rust supports it with dedicated targets; it is a young, fast-moving area, so read the current documentation before choosing it.

Common mistakes

  • Forgetting crate-type = ["cdylib"]: no usable .wasm is produced.
  • Opening the HTML file directly from disk. Use a local server (for example python -m http.server).
  • Expecting Wasm to speed up DOM-heavy code. It helps with computation, not with page updates.
  • Shipping a debug build: much larger and slower.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Rust and WebAssembly · 1/6

Wasm = near-native speed in the browser

WebAssembly is a fast binary format that runs in the browser next to JavaScript.

Prefer a video by a teacher? Find free videos on “rust webassembly wasm-bindgen wasm-pack tutorial” on YouTube ↗

In real life: Compressing photos on the user's phone

A government-form helper website lets users upload passport photos that must be under 50 KB. Instead of uploading the original 4 MB photo to a server, the site compresses it in the browser with a Rust library compiled to Wasm. It is fast, works even on a slow mobile connection, and the user's photo never leaves their phone until they submit it.

rust
use wasm_bindgen::prelude::*;

/// Turns RGBA pixels to greyscale in place; called from JavaScript with a Uint8Array.
#[wasm_bindgen]
pub fn greyscale(pixels: &mut [u8]) {
    for px in pixels.chunks_exact_mut(4) {
        let y = (0.299 * px[0] as f32 + 0.587 * px[1] as f32 + 0.114 * px[2] as f32) as u8;
        px[0] = y;
        px[1] = y;
        px[2] = y;
    }
}
One call processes the whole image buffer; JavaScript then draws it on a canvas.

Practice (0/3 done)

Task 1 · Question

Which job is the best fit for Rust compiled to WebAssembly?

Task 2 · Question

Which target compiles Rust to WebAssembly for the browser?

Task 3 · Practice

Create the emi_calc crate from this topic, build it with wasm-pack build --target web, and write an index.html with three inputs (amount, rate, months) and a button that shows the EMI using your Wasm function. Serve it locally and test it on your phone on the same Wi-Fi.

Quick quiz

Question 1

1.What is WebAssembly?

Question 2

2.What does wasm-bindgen do?

Question 3

3.Can Wasm change the page (DOM) directly?

Question 4

4.Which crate-type is needed to build a Wasm library for JavaScript?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

What is WebAssembly?

Answer: A compact binary format browsers run at near-native speed

Wasm is a compilation target supported by all major browsers.

What does wasm-bindgen do?

Answer: Generates glue so JavaScript and Rust can call each other

It handles type conversion between JS and Wasm.

Can Wasm change the page (DOM) directly?

Answer: No, it goes through JavaScript glue

DOM access goes through JS bindings.

Which crate-type is needed to build a Wasm library for JavaScript?

Answer: cdylib

cdylib produces a dynamic library that wasm-bindgen can wrap.

What does flutter build web --wasm produce?Related

Answer: A WebAssembly build of the web app

Faster in supporting browsers.

From Flutter on the web and desktop

How does Rust free memory?Related

Answer: Through ownership: a value is freed when its owner goes out of scope

Ownership rules make freeing automatic and predictable, and the compiler checks them.

From What Rust is and why learn it

Which area is a well-known public use of Rust?Related

Answer: Parts of the Linux kernel and cloud infrastructure

Rust is used in kernels, cloud services and tools.

From Where Rust is used and the job market

How often does Rust release a new stable version?Related

Answer: Every 6 weeks

Stable releases come every six weeks.

From Portfolio, open source and a learning plan

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. This is the last topic of “Real projects: CLI, web and WebAssembly”. The module exam comes next.
  2. Module 11 exam: Real projects · 13 questions · 25 min, without help. 4 topics of this module still to finish first.
  3. Then the next module, Rust careers and interviews. 50 topics left in the course before the final exam.

← Previous: Rust for the web with axum