Rust

1. Setup

Add the wasm32-wasip2 target to the Rust toolchain.

#![allow(unused)]
fn main() {
rustup target add wasm32-wasip2
}

Install wasmtime. The Wasmtime CLI has a built-in HTTP server that supports serving WebAssembly HTTP components.

curl https://wasmtime.dev/install.sh -sSf | bash

2. Creating a Rust WebAssemly project

Create a new Rust project with cargo new:

cargo new wasm-http-hello-world
cd wasm-http-hello-world

Add wstd, a Rust async standard library for Wasm components as a dependency with cargo add:

cargo add wstd

wstd provides idiomatic Rust bindings for WASI standard interfaces (wasi:http) to increase ease-of-use for Rust WebAssembly components. Since we are using wstd, we will not need to add WIT files or depend on wit-bindgen directly.

note

It is possible to build an HTTP component in Rust without wstd. Building a HTTP component without wstd would require defining the wasi:http imports/exports of the component in WIT, fetching WIT dependencies with wkg and generating the Rust bindings with wit-bindgen.

Both approaches are valid, but wstd offers superior developer experience, so we opt to use it here.

wstd and wit-bindgen are not mutually exclusive and can co-exist in the same project.

3. Writing the HTTP handler

We will implement the HTTP handler in src/main.rs. The file should look like the following:

use wstd::http::{Body, Request, Response, Result, StatusCode};

// WASI HTTP server components don't use a traditional `main` function.
// They export a function named `handle` which takes a `Request`
// argument, and which may be called multiple times on the same
// instance. To let users write a familiar `fn main` in a file
// named src/main.rs, wstd provides this `wstd::http_server` macro, which
// transforms the user's `fn main` into the appropriate `handle` function.
#[wstd::http_server]
async fn main(req: Request<Body>) -> Result<Response<Body>> {
    match req.uri().path() {
        "/" => home(req).await,
        _ => not_found(req).await,
    }
}

async fn home(_req: Request<Body>) -> Result<Response<Body>> {
    Ok(Response::new("Hello, world!\n".into()))
}

async fn not_found(_req: Request<Body>) -> Result<Response<Body>> {
    Ok(Response::builder()
        .status(StatusCode::NOT_FOUND)
        .body(().into())
        .expect("builder succeeds"))
}

4. Compiling and running the component

Build the component:

cargo build --release --target wasm32-wasip2

The .wasm binary for the component can be found at target/wasm32-wasip2/release/wasm-http-hello-world.wasm.

To run the component, we can use wasmtime, a reference implementation host that supports the Component Model.

In particular, we can use wasmtime serve subcommand, which will spin-up an HTTP server at http://localhost:8080 which will use our component to fulfill web requests. wasmtime creates a fresh instance of the component every time a request is served.

wasmtime serve -Scli -Shttp target/wasm32-wasip2/release/wasm-http-hello-world.wasm

You can test it with curl -i localhost:8080

HTTP/1.1 200 OK
transfer-encoding: chunked
date: Mon, 13 Apr 2026 23:22:20 GMT

Hello, world!

With this, we have successfully built and run a basic WebAssembly HTTP component with Rust 🎉

5. Going further

Explore more examples of projects that use wstd: