Wasm Outside the Browser (WASI)
What is WASI?
WASI (WebAssembly System Interface) lets Wasm run outside the browser — on servers, edge networks, IoT devices, and CLIs. It provides a standardized API for system capabilities that browsers don't need (file I/O, networking, etc.).
Browser Wasm WASI Wasm
┌───────────────┐ ┌───────────────┐
│ Web APIs │ │ System APIs │
│ (DOM, Canvas, │ │ (Files, Net, │
│ Fetch, etc.) │ │ Env, Clock) │
├───────────────┤ ├───────────────┤
│ Wasm Runtime │ │ Wasm Runtime │
│ (V8, Spider- │ │ (Wasmtime, │
│ Monkey) │ │ Wasmer) │
└───────────────┘ └───────────────┘Two Wasm Targets
| Target | Where it runs | APIs |
|---|---|---|
wasm32-unknown-unknown |
Browser | Web APIs via web-sys |
wasm32-wasip1 |
Server/CLI | WASI (files, env, args) |
Getting Started
# Add the WASI target
rustup target add wasm32-wasip1
# Install a WASI runtime
cargo install wasmtime-cli
# Create a project
cargo new --bin my-wasi-app
cd my-wasi-app// src/main.rs — works on WASI just like native Rust
use std::fs;
use std::env;
fn main() {
// Command-line args
let args: Vec<String> = env::args().collect();
println!("Args: {:?}", args);
// File I/O (sandboxed)
fs::write("output.txt", "Hello from WASI!").unwrap();
let content = fs::read_to_string("output.txt").unwrap();
println!("Read: {}", content);
// Environment variables
if let Ok(val) = env::var("MY_VAR") {
println!("MY_VAR = {}", val);
}
}# Build
cargo build --target wasm32-wasip1 --release
# Run with wasmtime (grant file access)
wasmtime --dir=. ./target/wasm32-wasip1/release/my-wasi-app.wasmCapability-Based Security
WASI uses a sandbox model — the Wasm module has NO access by default. You explicitly grant capabilities:
# No access to anything
wasmtime app.wasm
# Grant access to current directory
wasmtime --dir=. app.wasm
# Grant access to specific path
wasmtime --dir=/data::/app/data app.wasm
# Grant environment variables
wasmtime --env MY_VAR=hello app.wasmThis is fundamentally more secure than native executables — a Wasm module can't read your files, network, or environment unless you explicitly allow it.
Use Cases
| Use Case | Why WASI? |
|---|---|
| Edge computing (Cloudflare Workers) | Cold start ~1ms vs ~100ms for containers |
| Plugin systems | Safely run untrusted code in your app |
| CLI tools | Write once, run on any platform with a Wasm runtime |
| Serverless functions | Smaller, faster, more secure than containers |
| Embedded/IoT | Tiny runtime footprint (~5MB) |
WASI vs Browser Wasm
| Feature | Browser | WASI |
|---|---|---|
| DOM access | ✓ | ✗ |
| File system | ✗ | ✓ (sandboxed) |
| Network sockets | ✗ (Fetch only) | ✓ (sandboxed) |
| Startup time | ~100ms | ~1ms |
| Sandbox | Browser sandbox | Capability-based |
Cloudflare Workers Example
Cloudflare Workers can run WASI Wasm:
// A simple HTTP handler compiled to WASI
fn main() {
let body = "Hello from Rust + WASI on Cloudflare!";
println!("Content-Type: text/plain");
println!("Content-Length: {}", body.len());
println!();
print!("{}", body);
}The Future: Component Model
WASI is evolving toward the Component Model — composable Wasm modules that can import/export typed interfaces (not just bytes). This will enable:
- Wasm modules calling each other
- Language-agnostic interfaces
- Package managers for Wasm components
Try It
Click Run to see WASI capabilities. The code lists what WASI provides and how to compile for it. Try running it locally with wasmtime to see file I/O and env vars in action.
Try It
Chapter Quiz
Pass all questions to complete this lesson