WASI 0.3 Launched

Lobsters Hottest Tools

Summary

The article announces the launch of WASI 0.3, which integrates async primitives natively into WebAssembly components via the Component Model, simplifying APIs and enabling better component composition.

<p><a href="https://lobste.rs/s/kosw9h/wasi_0_3_launched">Comments</a></p>
Original Article
View Cached Full Text

Cached at: 06/12/26, 06:56 PM

# WASI 0.3 Launched Source: [https://bytecodealliance.org/articles/WASI-0.3](https://bytecodealliance.org/articles/WASI-0.3) **WASI 0\.3 is official, and async is now native to WebAssembly Components\.**The WASI Subgroup voted to ratify WASI 0\.3\.0, rebasing WASI onto the WebAssembly Component Model’s async primitives\. The 0\.3\.0 specification is now stable, and runtime and toolchain support is landing now\. The work that`wasi:io`in WASI 0\.2 used to do \(pollables, input\-streams, output\-streams\) is now part of[the canonical ABI](https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md), where the Component Model now offers these primitives natively\. As a concequence of that, most of the changes from WASI 0\.2 to 0\.3 are entirely*mechanical*and significantly simplify the signatures we had before\. The new async primitives are part of the Component Model’s[canonical ABI](https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md), enabling bindings generators to emit idiomatic async bindings for their given language\. ## The Component Model Async ABI In WASI 0\.2 each component needed its own event loop/async runtime\. That meant that individual components could be run on a host, but there was no way for those event loops to coordinate with one another\. If a component used streaming or async APIs, it couldn’t be composed with any other components\. WASI 0\.3 makes it so the host is now the one in charge of managing the one event loop that is shared by all components\. This is enabled by adding`stream<T\>`,`future<T\>`, and`async`as first\-class constructs to the canonical ABI: - `stream<T\>`and`future<T\>`function like resource types: each is an owned handle, passing one across a component boundary transfers ownership from caller to callee\. Unlike resource types, they can’t be borrowed\. - The runtime, not each component, drives the scheduling\. When a value has been delivered to a`future`, the runtime schedules whichever task is awaiting it, even if it was passed through multiple component boundaries\. The writer that delivers that value might be the host, another component, or even the same component that holds the read end\. - The async model is*completion\-based*, not*readiness\-based*\. This is similar to the ultra\-efficient Linux`io\_uring`and Windows’ IOCP/`IoRing`APIs\. An`epoll`/`kqueue`\-style readiness API can be emulated on top of this for programs which need the compatibility\. - Components export and import`async func`s directly\. Gone is the three\-step`start\-foo`/`finish\-foo`/`subscribe`dance from WASI 0\.2\. ## Changes to the WASI interfaces Most of the changes in the 0\.3 interfaces are entirely mechanical\. WASI 0\.2 had to perform some acrobatics to make async work, but now that async is native to the component model we can write the same things we did before but much more ergonomically\. Here is an overview of the patterns we were encoding in WASI 0\.2 with the`wasi:io`package, and what those patterns now look like in 0\.3 with Component Model async: WASI 0\.2 \(`wasi:io`\)WASI 0\.3 \(Component Model\)`resource pollable``future<T\>``resource input\-stream``stream<u8\>``resource output\-stream``stream<u8\>`\(written\-to direction\)`poll\(list<pollable\>\)``await`on a future \(runtime\-handled\)`subscribe\(\)`on resourcereturn a`future<\.\.\.\>`from the call`start\-foo`/`finish\-foo``foo: async func\(\.\.\.\)`A problem with WASI 0\.2 was that it surfaced terminal errors inline on each read call on the stream\. That meant callers only learned the outcome if they kept reading\. If readers stopped early they could not distinguish between a stream close and an error\. In WASI 0\.3 streams now return an additional future which resolves independently of how much of the stream is consumed, solving the stream status problem of WASI 0\.2: ``` // WASI 0.2 read-via-stream: func() -> result<input-stream, error-code>; // WASI 0.3 read-via-stream: func() -> tuple<stream<u8>, future<result<_, error-code>>>; ``` ## Changes to language bindings One of the super powers of the component model is that it makes it trivial to create bindings to and from other languages\. With the addition of first\-class async it means guest binding generators can leverage that to create async bindings that feel native to that language\. Take for example the`wasi:http/handler`interface\. This interface exposes one function,`handle`, which is marked async: ``` interface handler { handle: async func(request: request) -> result<response, error-code>; } ``` To implement an HTTP server in Rust with this, we can use the[wit\-bindgen](https://github.com/bytecodealliance/wit-bindgen/tree/main#guest-rust)crate\. This maps the`interface handler`to a`trait Guest`, and maps the`handle: async func`to an`async fn handle`: ``` use wasi::http::types::{ErrorCode, Request, Response}; impl Guest for Component { async fn handle(request: Request) -> Result<Response, ErrorCode> { // ... } } ``` Async support for guest binding generators is also in\-progress for many languages including[Python](https://github.com/bytecodealliance/componentize-py),[JavaScript](https://github.com/dicej/componentize-js),[C\#](https://github.com/bytecodealliance/wit-bindgen#guest-c), and[C](https://github.com/bytecodealliance/wit-bindgen/blob/main/crates/c/README.md)\. All of these languages rely on*stackless coroutines*\. But the Component Model’s async ABI was designed from the ground up to accomodate both*stackful*and*stackless*coroutines side\-by\-side\. An example of a language with those is Go\. Instead of exposing async and non\-async functions, Go’s runtime is able to convert synchronous\-looking calls to async calls, and provides concurrent execution via virtual threads called “goroutines”\. Using[componentize\-go](https://github.com/bytecodealliance/componentize-go/blob/2aa4ad80088ec18cd455cf9b5fecc0c9005fdffe/examples/wasip3/export_wasi_http_handler/handler.go)we can implement an HTTP server by exporting a`func Handle`\. This enables streaming bodies via goroutines that do blocking calls\. The runtime then parks the goroutine at the ABI boundary and resumes it when the stream is ready, without blocking the rest of the program: ``` package export_wasi_http_handler import ( . "wit_component/wasi_http_types" . "go.bytecodealliance.org/pkg/wit/types" ) func Handle(request *Request) Result[*Response, ErrorCode] { tx, rx := MakeStreamU8() // ← 1. Create a channel pair go func() { // ← 2. Spawn a virtual thread defer tx.Drop() tx.WriteAll([]uint8("Hello, world!")) // ← 3. Write into the channel }() response, send := ResponseNew( // ← 4. Create an HTTP response FieldsFromList([]Tuple2[string, []byte]{ {F0: "content-type", F1: []byte("text/plain")}, }).Ok(), Some(rx), // ← 5. Pass the receiver as the HTTP body trailersFuture(), ) send.Drop() return Ok[*Response, ErrorCode](response) // ← 6. Return the HTTP response } ``` Now that WASI 0\.3 has been launched with support for component model async, guest toolchains and host runtimes will be unblocked to begin stabilizing all of these\. Over the coming weeks and months you can expect individual projects to begin announcing support for WASI 0\.3\. ## Changes to`wasi:http` The interface that has seen the most change is`wasi:http`\. We haven’t just mechanically converted poll\-based interfaces to native async ones, but actually reorganized the worlds and changed some of the core abstractions\.`wasi:http`now exposes two worlds:`wasi:http/service`and`wasi:http/middleware`: ``` interface client { /* ... */ } interface handler { /* ... */ } // When used by guest bindings generators, grant the // ability to make HTTP calls through the `client` import, and // handle incoming HTTP requests through the `handler` export. world service { import client; export handler; } // The middleware world is a super-set of the service world. world middleware { include service; // ← Do everything that `service` can do. import handler; // ← But also pass incoming requests down to another handler. } ``` The`middleware`world replaces the 0\.2\-era`proxy`world, and is used to define HTTP handlers which can forward requests to other handlers\. What’s new in WASI 0\.3 is that this can now perform[service chaining](https://bytecodealliance.org/articles/how-wasm-components-enable-pluggable-middleware): a pattern where components can be directly composed with one another\. This means components acting as microservices that frequently interop with other microservices, do not need to go over the network\. Instead a runtime can choose to directly compose them with each other inside the same process\. For most microservices this will reduce the time for calling other microservices from milliseconds to nanoseconds: six orders of magnitude\. ## Conclusion We’re happy to share that WASI 0\.3 has been released\. That means that: - **Spec ratified**: WASI 0\.3 has passed the WASI Subgroup vote\. This is a stable release, which means programs you compile for it today are guaranteed to keep working in the future\. Even as we continue to release patch release every two months, e\.g\. 0\.3\.x\. - **Wasmtime**: Wasmtime 45 runs the latest release candidate today, and Wasmtime 46 will ship WASI 0\.3\.0 with Component Model Async enabled by default\. - **Jco close behind**: jco, the JavaScript Component Model toolchain, also supports all of WASI 0\.3\. A release that has support enabled by default will be going out soon\. - **Guest toolchains next\.**In parallel, work is in progress to enable WASI 0\.3 in guest toolchains\. As these release, you’ll be able to write WASI 0\.3 components in Rust, Go, JavaScript, Python, and more\. The best place to get started with WebAssembly Components is the[Wasm Component Model book](https://component-model.bytecodealliance.org/)\. For a comprehensive list of changes, see the[WASI 0\.3\.0 release notes](https://github.com/WebAssembly/WASI/releases/tag/v0.3.0)\. If you’re wondering what’s next for WebAssembly Components and WASI, see[The Road to Component Model 1\.0](https://bytecodealliance.org/articles/the-road-to-component-model-1-0)\. WASI 0\.3 is the work of a community\. Thank you to everyone in the WASI Subgroup who designed, debated, and refined this release, to the runtime and toolchain maintainers who built the implementations that make it real, and to every contributor who filed an issue, reviewed a PR, or asked the hard question that made the spec better\. And thank you to the users building on WASI; your components, your feedback, and your willingness to try release candidates shaped what shipped\. Component Model’s native async was years in the making, and it opens a new chapter: one where async and composability are first\-class, and where the same primitives serve every language\. We can’t wait to see what you build on it\. Welcome to WASI 0\.3\.

Similar Articles

WASI 0.3.0 Released

Hacker News Top

WASI 0.3.0 (Preview 3) has been released, replacing earlier explicit streams and polling interfaces with native async functionality via the component model's future and stream types.

weblings: Compiling Rust to WASM from inside WASM

Lobsters Hottest

Weblings is a Rust compiler toolchain compiled to WebAssembly, enabling compilation and execution of Rust code directly in the browser via a web UI with a playground and Rustlings exercises.

micropython-wasm 0.1a0

Simon Willison's Blog

micropython-wasm 0.1a0 released, enabling MicroPython to run in WebAssembly environments for sandboxing and portability.

luau-wasm 0.1a0

Simon Willison's Blog

luau-wasm 0.1a0, a WebAssembly build of the Luau scripting language, has been released.