Skip to main content
Back to Journal
WebAssemblyProgramming

WebAssembly Beyond the Browser: WASI and the Component Model

I have been following WebAssembly since it launched in browsers in 2017, and for a long time I thought of it primarily as a way to run C++ or Rust code on the web. That is still a valid use case, but the more exciting story in 2025 is what is happening outside the browser.

WASI (WebAssembly System Interface) gives Wasm modules access to system resources like files, network sockets, and clocks. The Component Model lets you compose Wasm modules written in different languages into a single application. Together, they are turning WebAssembly into a universal runtime for portable, sandboxed code.

What WASI Provides

Browser-based WebAssembly is sandboxed. It cannot access the filesystem, open network connections, or read environment variables. That is great for security in the browser, but it makes Wasm useless for server-side applications.

WASI defines a standard set of interfaces that let Wasm modules interact with the outside world in a controlled way. The host (the runtime that executes the Wasm module) decides which capabilities to grant. A module might be allowed to read files from a specific directory but nothing else. Or it might have network access but no filesystem access.

This capability-based security model is more granular than traditional process-level permissions. You can run untrusted code and know exactly what resources it can access.

WASI Preview 2

The first version of WASI (Preview 1) was limited. It provided basic filesystem and I/O operations but not much else. Preview 2, which has been stabilizing throughout 2024 and 2025, adds HTTP, sockets, clocks, random number generation, and a standardized way to define and consume interfaces.

The interface definition uses a language called WIT (Wasm Interface Type):

// hello.wit
package example:hello;

world hello {
  export greet: func(name: string) -> string;
}

This defines a component that exports a single function. Any language that compiles to Wasm can implement this interface, and any host can call it. The types are portable across language boundaries.

Runtimes

Several runtimes can execute WASI modules:

  • Wasmtime: The reference implementation, maintained by the Bytecode Alliance. Fast, well-documented, and supports Preview 2.
  • WasmEdge: Optimized for edge and IoT use cases. Has good integration with Kubernetes.
  • Spin by Fermyon: A framework for building serverless applications with Wasm. Opinionated but productive.

A Practical Example

Here is a simple Rust function compiled to WASI and called from Node.js.

The Rust side:

// lib.rs
#[no_mangle]
pub fn process_data(input: &str) -> String {
    let words: Vec<&str> = input.split_whitespace().collect();
    format!("Processed {} words", words.len())
}

Compile to WASI:

cargo build --target wasm32-wasi --release

The Node.js side using the Wasmtime npm package:

const { WASI } = require('wasi');
const fs = require('fs');

const wasi = new WASI({});
const wasm = await WebAssembly.compile(
  fs.readFileSync('./target/wasm32-wasi/release/my_lib.wasm')
);
const instance = await WebAssembly.instantiate(wasm, wasi.getImportObject());
wasi.start(instance);

The Wasm module runs in a sandbox. It cannot access your filesystem, network, or environment unless you explicitly grant those permissions through the WASI configuration. This is fundamentally different from running a native binary or even a Docker container.

The Component Model

The Component Model is the next evolution. Instead of monolithic Wasm modules, you can compose multiple components together, each written in a different language, communicating through typed interfaces.

Imagine a data pipeline where the parsing is written in Rust (for performance), the business logic is written in Python (for data scientist accessibility), and the HTTP handler is written in JavaScript (for web developer familiarity). Each component is compiled to Wasm independently and composed at runtime.

This is not theoretical. Tools like wasm-tools compose already let you wire components together. The tooling is still maturing, but the architecture is sound and the standards are stabilizing.

Real World Use Cases

Plugin systems are the most natural fit. Instead of running plugins as native code (security risk) or in a separate process (performance overhead), you run them as Wasm components with precisely scoped permissions. Figma, Shopify, and Envoy proxy all use Wasm for plugin execution.

Edge computing is another strong use case. Wasm modules start in microseconds (compared to milliseconds for containers), which matters for edge functions that need to handle requests with minimal latency. Cloudflare Workers and Fermyon Spin both support Wasm workloads.

Portable CLI tools are a third use case. Compile once to Wasm, distribute a single binary, and it runs on any platform with a Wasm runtime. No cross-compilation matrix, no platform-specific builds.

Compared to Containers

Docker containers are the current standard for portable deployment. Wasm is not going to replace Docker anytime soon, but it has advantages in specific scenarios.

Wasm modules are much smaller (often kilobytes vs megabytes for container images). They start much faster (microseconds vs seconds). They provide finer-grained sandboxing. And they are truly portable across CPU architectures without emulation.

The downside is ecosystem maturity. Docker has a decade of tooling, registries, orchestration (Kubernetes), and community knowledge. Wasm's server-side ecosystem is still young. The standards are mostly settled, but the tooling and best practices are still forming.

Where This Is Heading

I think WASI and the Component Model represent a genuine shift in how we think about portable, secure code execution. Not a revolution that replaces everything overnight, but a steady expansion of where Wasm makes sense. Five years from now, I expect Wasm components to be as normal as npm packages. We are in the early days, and that is exactly when it is worth paying attention.

wasmwasicomponent-modelwasmtimeserver-side