WASI 0.3
WASI 0.3 brings native async to WebAssembly components, moving asynchronous functionality that previously lived in the wasi:io package down into the Component Model itself. WASI 0.3.0 was released on June 11, 2026. This page provides an overview of what changed in WASI 0.3 and why.
Why native async?
In WASI 0.2, asynchronous operations were modeled with the wasi:io package, which provided pollable resources, input-stream and output-stream types, and a poll function. This system worked well when a component communicated directly with a host or a single peer, but broke down when components were composed in a chain.
Consider a scenario where component A calls component B, which in turn calls the host:
A → B → Host
In WASI 0.2, component B could not forward wake-ups from the host's pollable to component A, because pollable is a resource scoped to a single component instance. B would have to actively poll just to relay readiness signals. In practice, the wake-up chain gets dropped. This is sometimes called the sandwich problem: WASI 0.2 could express async, but could not compose it across component boundaries.
WASI 0.3 solves this by pushing async into the Component Model's Canonical ABI. The runtime owns the scheduling and wake-up propagation, so async works correctly regardless of how many components sit between a producer and a consumer.
New primitives
WASI 0.3 introduces three primitives built into the Component Model:
async func
Functions can now be declared as asynchronous in WIT. The runtime manages scheduling and suspension.
// A WASI 0.3 HTTP handler
handle: async func(request: request) -> result<response, error-code>;
Bindings generators emit language-native async constructs: async fn in Rust, Promise in JavaScript, coroutines in Python.
stream<T>
A typed, asynchronous data channel. Unlike input-stream and output-stream in WASI 0.2, a stream<T> is a value that can be passed across component boundaries.
// Reading from stdin in WASI 0.3
read-via-stream: func() -> tuple<stream<u8>, future<result<_, error-code>>>;
future<T>
A single-value async completion. Where WASI 0.2 used pollable resources, WASI 0.3 uses future<T> values.
// Writing to stdout in WASI 0.3
write-via-stream: func(data: stream<u8>) -> future<result<_, error-code>>;
Common patterns
The stream-plus-future pattern
A recurring pattern in WASI 0.3 pairs a stream<T> with a future that signals completion or error:
read-via-stream: func() -> tuple<stream<u8>, future<result<_, error-code>>>;
The stream delivers data incrementally. Once the stream closes, the future resolves to indicate whether the operation completed successfully or encountered an error. This pattern appears in stdin, filesystem reads, TCP receives, and directory listings.
The write direction flip
In WASI 0.2, write operations gave you an output-stream that you wrote into. In WASI 0.3, the direction is reversed: you pass in a stream<u8> and receive a future<result> that resolves when the write completes. This applies to stdout, stderr, filesystem writes, and TCP sends.
// WASI 0.2: get a stream, write to it
get-stdout: func() -> output-stream;
// WASI 0.3: pass data in, get a completion future
write-via-stream: func(data: stream<u8>) -> future<result<_, error-code>>;
Worlds
WASI 0.3 defines the following worlds across its core proposals:
wasi:cli/commandtargets command-line programs that export anasync func run(), with access to filesystem, environment variables, stdin/stdout/stderr, exit, and clocks/random/sockets imports.wasi:http/servicetargets HTTP servers that export an asynchandler, with imports from clocks, random, cli stdio, and the HTTP client interface. Theserviceworld replaceswasi:http/proxyfrom WASI 0.2.wasi:http/middlewareextendsserviceby also importing the handler interface, providing first-class support for request-path middleware components.
Each core proposal additionally exposes an imports world (wasi:cli/imports, wasi:sockets/imports, wasi:filesystem/imports, wasi:clocks/imports, wasi:random/imports) aggregating that package's interfaces for use by other worlds.
What changed in each interface
wasi:io (removed)
The entire wasi:io package has been removed. Its functionality is replaced by the Component Model's native stream<T>, future<T>, and async func primitives. There is no WASI 0.3 version of wasi:io.
WASI 0.2 (wasi:io) | WASI 0.3 (Component Model) |
|---|---|
resource pollable | future<T> |
resource input-stream | stream<u8> |
resource output-stream | stream<u8> (write direction) |
poll(list<pollable>) | await on a future |
subscribe() on resource | return a future from the call |
start-foo / finish-foo pattern | foo: async func(...) |
wasi:http
HTTP saw the most dramatic restructuring in WASI 0.3.
Resources dramatically simplified. The incoming-request, outgoing-request, incoming-response, outgoing-response, incoming-body, outgoing-body, future-trailers, future-incoming-response, and response-outparam resources are all gone, replaced by unified request and response resources with stream<u8> bodies and future trailers.
The handler is now an async func:
// WASI 0.3 handler
handle: async func(request: request) -> result<response, error-code>;
// WASI 0.3 client
send: async func(request: request) -> result<response, error-code>;
New worlds. The proxy world has been replaced by service. A new middleware world both imports and exports the handler, providing first-class support for request-path middleware components.
New header error variant. The header-error variant gains size-exceeded for headers that exceed the runtime's configured size limit.
wasi:sockets
Interfaces consolidated from 7 to 2. The network, instance-network, tcp, tcp-create-socket, udp, and udp-create-socket interfaces are consolidated into a unified types interface containing both tcp-socket and udp-socket resources. A separate ip-name-lookup interface handles DNS resolution.
The network resource is removed. Network access is now granted at the world level.
Async operations are simplified. All start-connect/finish-connect and start-listen/finish-listen pairs are replaced with single async func calls:
connect: async func(remote-address: ip-socket-address) -> result<_, error-code>;
TCP listen returns a stream of sockets:
listen: func() -> result<stream<tcp-socket>, error-code>;
New error variant. The error-code enum gains connection-broken (POSIX EPIPE), distinguishing writes that failed because the peer closed the connection from other reset or abort conditions.
wasi:cli
stdin, stdout, and stderr use stream<u8> with the stream-plus-future pattern. The run function is now async:
run: async func() -> result;
A new shared types interface defines the error-code enum used across CLI interfaces.
The wasi:cli/exit interface now exposes both exit(status: result) and exit-with-code(status-code: u8). The exit-with-code function was promoted from Phase 2 into the stable 0.3 interface in June 2026.
wasi:filesystem
Nearly all descriptor methods are now async func. Streaming reads and writes use the stream-plus-future pattern, and directory listing returns stream<directory-entry>:
read-directory: func() -> tuple<stream<directory-entry>, future<result<_, error-code>>>;
The error-code enum gains a catch-all other(option<string>) variant for errors not captured by the existing variants.
wasi:clocks
Interfaces and types have been renamed to align with POSIX and Rust std::time conventions:
| WASI 0.2 | WASI 0.3 |
|---|---|
wall-clock | system-clock |
datetime | instant |
The instant record now uses s64 for seconds (instead of u64), supporting pre-epoch timestamps.
The subscribe-instant and subscribe-duration functions (which returned pollable) are replaced with async func equivalents:
wait-until: async func(when: mark);
wait-for: async func(how-long: duration);
wasi:random
The len parameter is renamed to max-len on get-random-bytes and get-insecure-random-bytes. The rename reflects a semantic change: implementations may return fewer bytes than requested, so callers should loop until they have collected the desired amount.
Runtime and tooling support
WASI 0.3 support is available in:
- Wasmtime 46 and later, which enables WASI 0.3 and the
component-model-asyncfeature by default - jco for JavaScript environments
Wasmtime 46 is the first release to implement the final WASI 0.3.0 specification. Wasmtime 43 through 45 implement the 0.3.0-rc-2026-03-15 snapshot, and Wasmtime 41 and 42 the earlier 0.3.0-rc-2026-01-06 snapshot; all of these require -Sp3 -W component-model-async=y. Wasmtime 44 added initial wasi:tls@0.3.0-draft support.
wasmtime serve accepts either a WASI 0.3 or a WASI 0.2 component, falling back to the WASI 0.2 wasi:http/proxy world for components that do not export the 0.3 service world.
Implementing WASI 0.3.1 requires the Component Model features adopted in 0.3.0 (async lift and lower, future, and stream) plus those adopted in 0.3.1 (the map<K, V> type and the implements and external-id annotations), on top of the ungated baseline. See Component Model features for the full list.
Runtimes verify WASI 0.3 conformance against the shared wasi-testsuite. WASI 0.3 coverage is now running on Wasmtime and jco across Linux, macOS, and Windows.
Migrating from WASI 0.2
Migration to WASI 0.3 is not required in order to use a 0.3-capable runtime. As noted above, wasmtime serve runs both 0.3 and 0.2 components from the same binary, dispatching per component. The roadmap also notes that implementations may polyfill 0.2 in terms of 0.3, mapping 0.2 imports onto native 0.3 primitives at the host boundary.
To migrate:
- Pinning your toolchain to a consistent WASI 0.3 release. The Component Model defines canonical interface names so that components can link across compatible versions, but not all tools support this version-aware linking yet. Until they do, Wasmtime and the bindings generator (
wit-bindgenfor Rust,jcofor JavaScript, and so on) should target the same WIT version,0.3.0. Mismatches surface as confusingwrong typeerrors at instantiation. - Replacing
wasi:iotypes with their Component Model equivalents (see thewasi:io(removed) section above for the mapping). - Switching to the appropriate world:
wasi:cli/commandfor CLI programs,wasi:http/servicefor HTTP servers,wasi:http/middlewarefor middleware components. - Updating
start-foo/finish-foocall sites to use the correspondingasync funcdeclarations.
For a detailed migration guide with working examples, see Migrating from WASI 0.2 to WASI 0.3 in the Component Model documentation.
Patch releases
WASI 0.3 patch releases ship every two months on the release train. See the Roadmap for release timelines.
| Version | Changelog |
|---|---|
| 0.3.1 | Released August 11, 2026. Adopts the Component Model map<K, V> type and the implements and external-id annotations. WASI interfaces may use them from this release onward. See Component Model features for what each WASI version requires. |
| 0.3.0 | Released June 11, 2026. The initial WASI 0.3 release, rebasing WASI onto the Component Model's native async primitives. |