WASI 0.3 gives the WebAssembly Component Model a shared event loop
The ratified spec replaces per component schedulers with a host owned event loop, so async and streaming components can compose across boundaries.
The ratified spec replaces per component schedulers with a host owned event loop, so async and streaming components can compose across boundaries.
The barrier that kept WebAssembly components from composing with each other on async work was not a missing API. It was a missing scheduler. In WASI 0.2, every component that wanted to do anything asynchronous had to ship its own event loop, and that meant two components trying to compose the same async work ran on two independent schedulers ticking on two independent clocks. WASI 0.3, ratified by the WASI Subgroup, replaces that arrangement with a single host-owned event loop and a small set of new canonical-ABI primitives that make async a first-class part of the Component Model.
The headline change is the addition of three new primitives in the canonical ABI: stream<T>, future<T>, and async itself (WASI 0.3 announcement). These are not borrowable handles. They are owned values whose ownership transfers across component boundaries, and the runtime, not the component, decides when work runs. Bindings generators can now emit idiomatic async for their host language, which is what made the old start-foo, finish-foo, subscribe dance necessary in the first place.
The scheduling model is completion-based rather than readiness-based. Components do not poll to ask whether they are ready. They hand work to the host and get notified when it finishes. The pattern is the same one Linux io_uring and Windows IOCP / IoRing use, and the WASI 0.3 announcement is explicit that the design should look familiar to systems programmers used to those interfaces. For components that depend on the older readiness model, epoll-style and kqueue-style APIs can be emulated on top of the new primitives rather than rebuilt from scratch.
What this buys you, in practice, is composition. In WASI 0.2, an HTTP middleware component and a service component that both wanted to do async I/O could not talk to each other without one of them owning a scheduler the other could not reach. The 0.3 release reorganizes wasi:http into two worlds, wasi:http/service and wasi:http/middleware, and the middleware world is built around direct in-process chaining rather than network calls. The Bytecode Alliance characterizes the result: for typical microservice-to-microservice calls, the announcement claims in-process chaining takes call latency from milliseconds to nanoseconds, roughly six orders of magnitude. That figure is the standards body's own estimate, not an independent benchmark, and it applies to in-process composition rather than the network call the same components would have made otherwise.
The interface changes from 0.2 to 0.3 are described in the announcement as mostly mechanical. Streams now return an independent future<result<_, error-code>>, which separates a terminal error from an early close, a case the old API conflated. The WASI 0.2 wasi:io surface of pollables, input-streams, and output-streams has been folded into the canonical ABI.
Runtime support is landing, not finished. Wasmtime 45 already runs the latest 0.3 release candidate. Wasmtime 46 is on the way with WASI 0.3.0 and Component Model Async enabled by default. jco, the JavaScript Component Model toolchain, supports the full 0.3 surface today, with a default-enabled release coming soon. Guest-language support is moving in parallel: wit-bindgen for Rust, componentize-py for Python, componentize-js for JavaScript, wit-bindgen for C# and C, and componentize-go for Go. The async ABI was designed to host both stackful and stackless coroutines side by side, so languages that prefer one style do not have to wait on the other.
The honest framing: this is a ratified spec with a 0.3.x patch cadence planned every two months. The real test is whether host runtimes expose the shared scheduler to user code, and whether bindings generators ship idiomatic async across each language they target. Those are implementation questions, not specification questions, and they are the ones to watch.