Skip to content

Building Components

Build wasi:http/incoming-handler@0.2.0 components in any language that can run on mik or any WASI HTTP runtime.

mik uses WASI HTTP 0.2.0. When building components, use matching WIT definitions.

LanguageSDK/ToolchainRaw SizeStripped
C/C++wasi-sdk + wit-bindgen~88 KB~25 KB
Rustwit-bindgen / mik-sdk~100 KB~100 KB
JavaScriptjco (ComponentizeJS)~12 MB~12 MB
Pythoncomponentize-py~39 MB~17 MB

Tip: Use mik strip component.wasm to remove debug info and names (auto-downloads wasm-tools if needed), or directly: wasm-tools strip --all component.wasm -o stripped.wasm

Terminal window
# C/C++ (wasi-sdk 25+)
# Download from https://github.com/WebAssembly/wasi-sdk/releases
cargo install wit-bindgen-cli # For generating C bindings
# Rust
rustup target add wasm32-wasip2
cargo install cargo-component wasm-tools
# JavaScript
npm install -g @bytecodealliance/jco @bytecodealliance/componentize-js
# Python
pip install componentize-py
# Or use uv: uv run --with componentize-py componentize-py ...

Rust produces compact components. Two options available.

Terminal window
mik new my-handler
cd my-handler
src/lib.rs
#[allow(warnings)]
mod bindings;
use bindings::exports::mik::core::handler::{self, Guest, Response};
use mik_sdk::prelude::*;
routes! {
GET "/" | "" => hello,
}
fn hello(_req: &Request) -> Response {
ok!({
"message": "Hello from Rust!",
"lang": "rust"
})
}
dist/my-handler-composed.wasm
mik build -rc
Terminal window
cargo new --lib my-component && cd my-component
cargo add wit-bindgen
Cargo.toml
[lib]
crate-type = ["cdylib"]
Terminal window
cargo component build --release

C produces the smallest components using wasi-sdk.

Terminal window
mkdir hello-c && cd hello-c
# Get WASI HTTP 0.2.0 WIT
git clone --depth 1 --branch v0.2.0 https://github.com/WebAssembly/wasi-http.git
# Generate C bindings
wit-bindgen c wasi-http/wit --out-dir gen --world proxy
hello.c
#include "gen/proxy.h"
#include <string.h>
static const char* RESPONSE_BODY = "{\"message\":\"Hello from C!\",\"lang\":\"c\"}";
void exports_wasi_http_incoming_handler_handle(
exports_wasi_http_incoming_handler_own_incoming_request_t request,
exports_wasi_http_incoming_handler_own_response_outparam_t response_out
) {
wasi_http_types_incoming_request_drop_own(request);
// Create response
wasi_http_types_own_fields_t headers = wasi_http_types_constructor_fields();
wasi_http_types_own_outgoing_response_t response =
wasi_http_types_constructor_outgoing_response(headers);
wasi_http_types_borrow_outgoing_response_t resp_borrow =
(wasi_http_types_borrow_outgoing_response_t){ response.__handle };
wasi_http_types_method_outgoing_response_set_status_code(resp_borrow, 200);
// Get body and stream
wasi_http_types_own_outgoing_body_t body;
wasi_http_types_method_outgoing_response_body(resp_borrow, &body);
wasi_io_streams_own_output_stream_t stream;
wasi_http_types_borrow_outgoing_body_t body_borrow =
(wasi_http_types_borrow_outgoing_body_t){ body.__handle };
wasi_http_types_method_outgoing_body_write(body_borrow, &stream);
// Set response before writing
wasi_http_types_result_own_outgoing_response_error_code_t result = {
.is_err = false, .val.ok = response
};
wasi_http_types_static_response_outparam_set(response_out, &result);
// Write body
proxy_list_u8_t body_bytes = { (uint8_t*)RESPONSE_BODY, strlen(RESPONSE_BODY) };
wasi_io_streams_stream_error_t err;
wasi_io_streams_borrow_output_stream_t stream_borrow =
(wasi_io_streams_borrow_output_stream_t){ stream.__handle };
wasi_io_streams_method_output_stream_blocking_write_and_flush(stream_borrow, &body_bytes, &err);
wasi_io_streams_output_stream_drop_own(stream);
wasi_http_types_error_code_t body_err;
wasi_http_types_static_outgoing_body_finish(body, NULL, &body_err);
}
Terminal window
# Set WASI_SDK to your installation path
WASI_SDK=/path/to/wasi-sdk
$WASI_SDK/bin/clang --target=wasm32-wasip2 -O2 \
-c gen/proxy.c -o proxy.o
$WASI_SDK/bin/clang --target=wasm32-wasip2 -O2 \
-c hello.c -o hello.o
$WASI_SDK/bin/clang --target=wasm32-wasip2 -O2 \
proxy.o hello.o gen/proxy_component_type.o -o hello-c.wasm

Uses jco (ComponentizeJS).

Terminal window
mkdir hello-js && cd hello-js
npm install @bytecodealliance/jco @bytecodealliance/componentize-js
# Get WASI HTTP 0.2.0 WIT
git clone --depth 1 --branch v0.2.0 https://github.com/WebAssembly/wasi-http.git
cp -r wasi-http/wit .
app.js
import {
ResponseOutparam,
OutgoingBody,
OutgoingResponse,
Fields,
} from "wasi:http/types@0.2.0";
export const incomingHandler = {
handle(_incomingRequest, responseOutparam) {
const response = new OutgoingResponse(new Fields());
response.setStatusCode(200);
let body = response.body();
let stream = body.write();
stream.blockingWriteAndFlush(
new Uint8Array(
new TextEncoder().encode(
JSON.stringify({
message: "Hello from JavaScript!",
lang: "javascript",
})
)
)
);
stream[Symbol.dispose]();
OutgoingBody.finish(body, undefined);
ResponseOutparam.set(responseOutparam, { tag: "ok", val: response });
},
};
Terminal window
npx jco componentize app.js --wit wit --world-name proxy -o hello-js.wasm

Uses componentize-py.

Terminal window
mkdir hello-python && cd hello-python
# Get WASI HTTP 0.2.0 WIT
git clone --depth 1 --branch v0.2.0 https://github.com/WebAssembly/wasi-http.git
cp -r wasi-http/wit .
Terminal window
# Using pip
componentize-py -d wit -w proxy bindings .
# Or using uv (recommended)
uv run --with componentize-py componentize-py -d wit -w proxy bindings .
app.py
from wit_world import exports
from componentize_py_types import Ok
from wit_world.imports.types import (
IncomingRequest, ResponseOutparam, OutgoingResponse, Fields, OutgoingBody
)
class IncomingHandler(exports.IncomingHandler):
def handle(self, _: IncomingRequest, response_out: ResponseOutparam):
response = OutgoingResponse(Fields.from_list([
("content-type", b"application/json"),
]))
response.set_status_code(200)
body = response.body()
# IMPORTANT: Set response BEFORE writing body
ResponseOutparam.set(response_out, Ok(response))
body.write().blocking_write_and_flush(
b'{"message":"Hello from Python!","lang":"python"}'
)
OutgoingBody.finish(body, None)
Terminal window
# Using pip
componentize-py -d wit -w proxy componentize app -o hello-python.wasm
# Or using uv (recommended)
uv run --with componentize-py componentize-py -d wit -w proxy componentize app -o hello-python.wasm

Terminal window
# Check exports
wasm-tools component wit my-component.wasm | grep "export wasi:http"
# export wasi:http/incoming-handler@0.2.0
# Run with mik
mik run my-component.wasm
# Test
curl http://localhost:3000/run/my-component/

IssueSolution
module requires import interface wasi:http/typesUse wasi-http v0.2.0 WIT (not latest)
ResponseOutparam.set is not a function (JS)Use { tag: 'ok', val: response }
missing Ok wrapper (Python)Import Ok from componentize_py_types
Empty responseCall ResponseOutparam.set() BEFORE writing body
mikwasmtimewasi-http WIT
0.0.140.0.00.2.0