Why WebAssembly components
— 2026-03-12

Yesterday Making WebAssembly a First-Class Language on the Web was making the rounds on social media, and I saw some people express confusion about this Wasm Component business. Why would the folks working on WebAssembly be going through all this trouble to implement something on top of WebAssembly? And why is that interesting for browser vendors like Firefox to begin implementing?

The way I’ve started explaining this is by drawing parallels between WebAssembly and other host platforms like Linux and Windows. Wasm is a little different from most other host platforms in that it is virtual. Instead of producing platform-specific assembly directly it produces virtual assembly that can be converted to platform-specific assembly later on. And instead of hosting its own kernel, Wasm hosts are typically run on top of another host.

But WebAssembly itself is just instructions. It can operate on numbers, pointers, and not much more. To interact with host APIs - both on and off the web - it needs to define an ABI and setup glue code in both the host and Wasm guest to bridge one to the other.

This is not Wasm-specific however: every host has to do this. Typically there are four total layers which need to be defined for this to work:

  1. The instruction format that the underlying hardware uses: e.g. x86, ARM, etc.
  2. The container format that the instructions will be packaged as: e.g. ELF, exe, Mach-O, etc.
  3. The IDL used to define which system calls are available: e.g. C headers, WinMD, Mach IDL, etc.
  4. The actual system calls themselves: e.g. Win32, POSIX, Darwin, etc.

Wasm Components are just a container format (2) for core Wasm instructions. Which uses an IDL (3) to define which APIs the container can import and export. One of those sets on system calls (4) is WASI: the WebAssembly System Interfaces. But Wasm Components are not tied to just WASI: the entire stack can be reused to target the Web as well. That’s what “Making WebAssembly First-Class on the Web” is about.

For reference: here are Linux, Windows, macOS, and WebAssembly side-by-side in a table:

WebAssemblyLinuxWindowsmacOS
Instruction FormatCore Wasmx86, ARM, etc.x86, ARMARM
Container FormatWasm ComponentsExecutable and Linkable Format (ELF)Portable Executable (PE)Mach-O
Interface Definition LanguageWasm Interface Types (WIT)C header filesWindows Metadata (WinMD)(Objective-)C header files + Mach IDL + Swift Modules
System InterfacesWasm System Interface (WASI)POSIX + Linux User-Space APIsWin32 + UWPPOSIX + Darwin Syscalls

Without Wasm Components standardizing the instruction packaging, composition, and ABI - every Wasm ecosystem will need to decide those things on their own. We saw this in the early days of Wasm where the output of wasm-bindgen was an entirely different format from what was used for WASI 0.1. Which is partially why we never saw support for a “wasm-web” target land in the Rust compiler.

This is changing with Wasm Components however. We’ve added a Wasm Component project goal to the Rust 2026 roadmap which includes:

  1. Adding new Wasm Component targets with native support for async/concurrency (wasm32-component, wasm32-wasip3).
  2. Adding support for std::thread to the wasm32-wasip3 target.
  3. Implementing async fn main for the wasm32-wasip3 target
  4. Adding support for a new wasm32-component-web target.

The idea is for the web target to be identical to the wasm32-component target, except that it will have access to something along the lines of #[cfg(web)] which is important to build a crates ecosystem around. And the wasm32-component target will be almost identical to the wasm32-wasip3 target, except that it will only implement core and alloc, but not std.

To start closing this out: none of this work would be practical without a standard packaging format for Wasm instructions. For the same reasons that it would be madness if e.g. gcc, clang, and msvc all disagreed on what a binary for Windows should look like. Wasm Components fill a role that every host system has their own solutions for. And I for one am happy that we’re finally closing the gap here; slowly landing on a single format that can work both on and off the web, and is natively supported by compilers.