diff --git a/component-model/src/language-support/creating-runnable-components/rust.md b/component-model/src/language-support/creating-runnable-components/rust.md
index a497c3e..8e7f8f1 100644
--- a/component-model/src/language-support/creating-runnable-components/rust.md
+++ b/component-model/src/language-support/creating-runnable-components/rust.md
@@ -1,5 +1,13 @@
# Creating Runnable Components (Rust)
+
+
+This page has content for both **WASI 0.2** and **WASI 0.3**. Use the tabs below to switch between versions where they differ.
+
+> **WASI 0.3 toolchain note.** Rust's [`wasm32-wasip3` target](https://doc.rust-lang.org/nightly/rustc/platform-support/wasm32-wasip3.html) is currently Tier 3 with no prebuilt artifacts; building for it requires constructing the standard library from source. The 0.3 example on this page therefore uses the library/reactor pattern targeting `wasm32-wasip2`, where [`wit-bindgen`](https://crates.io/crates/wit-bindgen)'s `async` feature handles the 0.3 binding generation. There is no Rust-idiomatic 0.3 path for the `fn main()` command-component pattern yet.
+
+
+
## Creating a command component
A _command_ is a component with a specific export that allows it to be executed directly by `wasmtime`
@@ -45,7 +53,7 @@ cargo build --target=wasm32-wasip2
The component can also be built in release mode:
-```console
+```sh
cargo build --target=wasm32-wasip2 --release
```
@@ -57,6 +65,8 @@ To run your command component:
wasmtime run ./target/wasm32-wasip2/debug/runnable-example.wasm
```
+> For a runnable component that exports the 0.3 `wasi:cli/run` interface, see the library/reactor pattern below.
+
## Enabling a library component to be run via the `wasi:cli/run` interface
Sometimes, it is useful to create a component that can *both* be used as a library (via
@@ -91,15 +101,28 @@ crate-type = ['cdylib']
We'll also be generating Rust bindings from WIT interfaces, so add `wit-bindgen`:
+{{#tabs global="wasi-version" }}
+{{#tab name="WASI 0.2" }}
```sh
cargo add wit-bindgen
```
+{{#endtab }}
+{{#tab name="WASI 0.3" }}
+```sh
+cargo add wit-bindgen --features async
+```
+
+The `async` feature enables `wit-bindgen`'s async code generation, which is needed for the 0.3 `async func run()` signature.
+{{#endtab }}
+{{#endtabs }}
### 2. Add the appropriate WIT interfaces
Then, add the appropriate WIT interfaces. For example a simple component that prints "Hello World", add the following
contents to `runnable-example/wit/component.wit`:
+{{#tabs global="wasi-version" }}
+{{#tab name="WASI 0.2" }}
```wit
package example:runnable;
@@ -112,6 +135,26 @@ world greeter {
export wasi:cli/run@0.2.7;
}
```
+{{#endtab }}
+{{#tab name="WASI 0.3" }}
+```wit
+package example:runnable;
+
+interface greet {
+ greet: func(name: string) -> string;
+}
+
+world greeter {
+ export greet;
+ export wasi:cli/run@0.3.0-rc-2026-03-15;
+}
+```
+
+In WASI 0.3, `wasi:cli/run` is declared as `run: async func() -> result`, so the generated `Guest` trait expects an `async fn`.
+
+> The pin here is `0.3.0-rc-2026-03-15` rather than the published `0.3.0` because Wasmtime, `wit-bindgen`, and other toolchain components currently ship this snapshot of the WIT. They are expected to refresh to `0.3.0` in upcoming releases.
+{{#endtab }}
+{{#endtabs }}
Building a library component this way does two things:
@@ -126,6 +169,8 @@ using `wkg`:
wkg wit fetch
```
+> For WASI 0.3, use `wkg` 0.15 or later. Earlier versions fail to decode the `wasi:cli@0.3.0-rc-2026-03-15` package.
+
At this point, you should have a `wit` folder with a `deps` subfolder and your original `component.wit`.
The component we will create to satisfy the WIT above can be used as a library, as other components
@@ -139,6 +184,8 @@ with any tooling (ex. `wasmtime run`) that supports/recognizes the `wasi:cli` in
The following code can be inserted into `runnable-example/src/lib.rs`:
+{{#tabs global="wasi-version" }}
+{{#tab name="WASI 0.2" }}
```rust
mod bindings {
use super::Component;
@@ -166,9 +213,43 @@ impl bindings::exports::wasi::cli::run::Guest for Component {
}
}
```
+{{#endtab }}
+{{#tab name="WASI 0.3" }}
+```rust
+mod bindings {
+ use super::Component;
+
+ wit_bindgen::generate!();
+
+ export!(Component);
+}
+
+/// Component off of which implementation will hang (this can be named anything)
+struct Component;
+
+/// Implementation for the `greet` interface export
+impl bindings::exports::example::runnable::greet::Guest for Component {
+ fn greet(name: String) -> String {
+ format!("Hello {name}!")
+ }
+}
+
+/// Implementation for `wasi:cli/run` interface export.
+/// In WASI 0.3 the `run` function is asynchronous.
+impl bindings::exports::wasi::cli::run::Guest for Component {
+ async fn run() -> Result<(), ()> {
+ eprintln!("Hello World!");
+ Ok(())
+ }
+}
+```
+{{#endtab }}
+{{#endtabs }}
### 4. Build the component
+{{#tabs global="wasi-version" }}
+{{#tab name="WASI 0.2" }}
To build the component, use `cargo`:
```sh
@@ -177,16 +258,49 @@ cargo build --target=wasm32-wasip2
The component can also be built in release mode:
-```console
+```sh
cargo build --target=wasm32-wasip2 --release
```
+{{#endtab }}
+{{#tab name="WASI 0.3" }}
+Build the component against `wasm32-wasip2` using a nightly Rust toolchain:
+
+```sh
+cargo +nightly build --target=wasm32-wasip2
+```
+
+Release mode:
+
+```sh
+cargo +nightly build --target=wasm32-wasip2 --release
+```
+
+> A nightly toolchain is required because the `wasm-component-ld` bundled with current stable Rust cannot decode the component-type custom section that `wit-bindgen` 0.58 emits for 0.3 worlds. Nightly ships a newer linker that handles it.
+{{#endtab }}
+{{#endtabs }}
### 5. Run the component with `wasmtime`
+{{#tabs global="wasi-version" }}
+{{#tab name="WASI 0.2" }}
You can run the component with `wasmtime`, and unlike a generic reactor component, you do not need to specify
the interface and function to run (`wasi:cli/run` is detected and used automatically):
```console
-$ wasmtime run target/wasm32-wasip2/runnable-example.wasm
+$ wasmtime run target/wasm32-wasip2/debug/runnable_example.wasm
+Hello World!
+```
+
+> Cargo converts hyphens to underscores in library crate names, so the artifact is `runnable_example.wasm` even though the package was created as `runnable-example`.
+{{#endtab }}
+{{#tab name="WASI 0.3" }}
+Enable the WASI 0.3 ABI when running a 0.3 component, with Wasmtime 43 or later:
+
+```console
+$ wasmtime run -Sp3 -W component-model-async=y target/wasm32-wasip2/debug/runnable_example.wasm
Hello World!
```
+{{#endtab }}
+{{#endtabs }}
+
+> **Version pinning.** WASI 0.3 tools (`wit-bindgen`, Wasmtime, jco, and so on) must all target the same WIT version. As of WASI 0.3.0's release on 2026-06-11, `wit-bindgen` 0.58 and Wasmtime 45 still ship the `0.3.0-rc-2026-03-15` snapshot of the WIT; pinning to the published `0.3.0` produces `no exported instance named wasi:cli/run@0.2.6` (or similar) errors at run time until those tools refresh. Use the RC pin until then.