propeller logo

Addition (WASM Component)

Addition example using the WASM Component Model with an external wasmtime runtime

This example demonstrates running a WASM Component Model binary on propeller. Unlike the module mode example which passes arguments via --invoke CLI flags, component mode uses WAVE-encoded inputs — the proplet calls the exported function by name, constructing the wasmtime invocation internally.

The task name must exactly match the exported function name in the WIT interface. The proplet uses the task name to determine which component export to call. If they don't match, the proplet looks for a non-existent export and the task fails.

This example requires the external wasmtime runtime. Set the PROPLET_EXTERNAL_WASM_RUNTIME environment variable before starting proplet:

export PROPLET_EXTERNAL_WASM_RUNTIME="/usr/local/bin/wasmtime"
make start-proplet

The proplet logs should confirm the external runtime is in use:

2026-03-24T10:06:48.432355Z  INFO Starting Proplet (Rust) - Client ID: ab606a2f-8dde-4246-965e-cdf568d0b1d7
2026-03-24T10:06:48.432825Z  INFO MQTT client created (TLS: false)
2026-03-24T10:06:48.433370Z  INFO Starting MQTT event loop
2026-03-24T10:06:48.434037Z  INFO Using external Wasm runtime: wasmtime
2026-03-24T10:06:48.454048Z DEBUG Received MQTT packet: ConnAck(ConnAck { session_present: true, code: Success })
2026-03-24T10:06:48.542809Z  INFO Starting PropletService
2026-03-24T10:06:48.550090Z DEBUG Published to topic: m/ea972377-722e-4936-8f2a-2e0fde0fcd0d/c/5903b703-fbdc-4a0e-94d1-fafd0fbc8048/control/proplet/create
2026-03-24T10:06:48.550132Z  INFO Published discovery message
2026-03-24T10:06:48.550164Z  INFO Subscribed to topic: m/ea972377-722e-4936-8f2a-2e0fde0fcd0d/c/5903b703-fbdc-4a0e-94d1-fafd0fbc8048/control/manager/start
2026-03-24T10:06:48.550201Z  INFO Subscribed to topic: m/ea972377-722e-4936-8f2a-2e0fde0fcd0d/c/5903b703-fbdc-4a0e-94d1-fafd0fbc8048/control/manager/stop
2026-03-24T10:06:48.550224Z  INFO Subscribed to topic: m/ea972377-722e-4936-8f2a-2e0fde0fcd0d/c/5903b703-fbdc-4a0e-94d1-fafd0fbc8048/registry/server
2026-03-24T10:06:48.553268Z DEBUG Published to topic: m/ea972377-722e-4936-8f2a-2e0fde0fcd0d/c/5903b703-fbdc-4a0e-94d1-fafd0fbc8048/control/proplet/alive
2026-03-24T10:06:48.553322Z DEBUG Published liveliness update
2026-03-24T10:06:48.559778Z DEBUG Published to topic: m/ea972377-722e-4936-8f2a-2e0fde0fcd0d/c/5903b703-fbdc-4a0e-94d1-fafd0fbc8048/control/proplet/metrics
2026-03-24T10:06:48.559830Z DEBUG Published proplet metrics
2026-03-24T10:06:48.571194Z DEBUG Received MQTT packet: PubAck(PubAck { pkid: 1 })
2026-03-24T10:06:48.593042Z DEBUG Received MQTT packet: SubAck(SubAck { pkid: 2, return_codes: [Success(AtLeastOnce)] })
2026-03-24T10:06:48.608689Z DEBUG Received MQTT packet: SubAck(SubAck { pkid: 3, return_codes: [Success(AtLeastOnce)] })
2026-03-24T10:06:48.617953Z DEBUG Received MQTT packet: SubAck(SubAck { pkid: 4, return_codes: [Success(AtLeastOnce)] })
2026-03-24T10:06:48.640170Z DEBUG Received MQTT packet: PubAck(PubAck { pkid: 5 })
2026-03-24T10:06:48.653908Z DEBUG Received MQTT packet: PubAck(PubAck { pkid: 6 })

Source Code

The source code is available in the examples/add-component directory.

The WIT interface defines a single exported function:

Loading...

The Rust implementation:

Loading...

Build the Component

You need the following tools installed:

  • Rust with the wasm32-wasip2 target: rustup target add wasm32-wasip2
  • wasm-tools v0.200 or later
cd propeller/examples/add-component
cargo build --target wasm32-wasip2 --release

Your output should look like this:

   Compiling add-component v0.1.0
    Finished `release` profile [optimized] target(s) in 2.37s

The wasm32-wasip2 target produces a WASM Component Model binary directly — no additional wasm-tools component new step is needed.

Create Task

The task name must exactly match the WIT export function name — the proplet uses it to construct the wasmtime invocation (--invoke "add(1, 2)"). The inputs array contains the arguments, WAVE-encoded as strings.

curl -X POST "http://localhost:7070/tasks" -H "Content-Type: application/json" -d '{"name": "add", "inputs": ["1", "2"]}'

Your output should look like this:

{
    "id": "ab375ffe-05c4-4d26-8dd1-498108708f7d",
    "name": "add",
    "kind": "standard",
    "state": 0,
    "cli_args": null,
    "inputs": [
        "1",
        "2"
    ],
    "daemon": false,
    "encrypted": false,
    "start_time": "0001-01-01T00:00:00Z",
    "finish_time": "0001-01-01T00:00:00Z",
    "created_at": "2026-03-24T12:00:24.758955481Z",
    "updated_at": "0001-01-01T00:00:00Z",
    "next_run": "0001-01-01T00:00:00Z",
    "priority": 50
}

Upload Wasm

Upload the component binary using the task ID from the previous step:

curl -X PUT "http://localhost:7070/tasks/ab375ffe-05c4-4d26-8dd1-498108708f7d/upload" -F "file=@target/wasm32-wasip2/release/add_component.wasm"

Your output should look like this:

{
    "id": "ab375ffe-05c4-4d26-8dd1-498108708f7d",
    "name": "add",
    "kind": "standard",
    "state": 0,
    "file": "...<redacted>...",
    "cli_args": null,
    "inputs": [
        "1",
        "2"
    ],
    "daemon": false,
    "encrypted": false,
    "start_time": "0001-01-01T00:00:00Z",
    "finish_time": "0001-01-01T00:00:00Z",
    "created_at": "2026-03-24T12:00:24.758955481Z",
    "updated_at": "2026-03-24T12:00:29.473743792Z",
    "next_run": "0001-01-01T00:00:00Z",
    "priority": 50
}

Start Task

curl -X POST "http://localhost:7070/tasks/ab375ffe-05c4-4d26-8dd1-498108708f7d/start"

Your output should look like this:

{ "started": true }

The proplet logs will show the task being dispatched to the external wasmtime runtime:

2026-03-24T12:00:34.873498Z  INFO Received start command for task: ab375ffe-05c4-4d26-8dd1-498108708f7d
2026-03-24T12:00:34.884664Z  INFO Starting Host runtime app: task_id=ab375ffe-05c4-4d26-8dd1-498108708f7d, function=add, daemon=false, wasm_size=12559
2026-03-24T12:00:34.885742Z  INFO Setting 1 environment variables for task ab375ffe-05c4-4d26-8dd1-498108708f7d
2026-03-24T12:00:34.887482Z  INFO Running in synchronous mode, waiting for task: ab375ffe-05c4-4d26-8dd1-498108708f7d
2026-03-24T12:00:34.989209Z  INFO Process completed for task: ab375ffe-05c4-4d26-8dd1-498108708f7d
2026-03-24T12:00:34.989617Z DEBUG Cleaned up temporary file: "/tmp/proplet_ab375ffe-05c4-4d26-8dd1-498108708f7d.wasm"
2026-03-24T12:00:34.989729Z  INFO Task ab375ffe-05c4-4d26-8dd1-498108708f7d completed successfully. Result: 3
2026-03-24T12:00:34.989755Z  INFO Publishing result for task ab375ffe-05c4-4d26-8dd1-498108708f7d
2026-03-24T12:00:34.989817Z  INFO Successfully published result for task ab375ffe-05c4-4d26-8dd1-498108708f7d

Get Results

curl -X GET "http://localhost:7070/tasks/ab375ffe-05c4-4d26-8dd1-498108708f7d"

Your output should look like this:

{
    "id": "ab375ffe-05c4-4d26-8dd1-498108708f7d",
    "name": "add",
    "kind": "standard",
    "state": 3,
    "file": "...<redacted>...",
    "cli_args": null,
    "inputs": [
        "1",
        "2"
    ],
    "daemon": false,
    "encrypted": false,
    "proplet_id": "ab606a2f-8dde-4246-965e-cdf568d0b1d7",
    "results": "3\n",
    "start_time": "2026-03-24T12:00:34.870381026Z",
    "finish_time": "2026-03-24T12:00:35.026898367Z",
    "created_at": "2026-03-24T12:00:24.758955481Z",
    "updated_at": "2026-03-24T12:00:35.026898016Z",
    "next_run": "0001-01-01T00:00:00Z",
    "priority": 50
}

State 3 means the task completed successfully. The results field shows "3\n" — the return value of add(1, 2).

How It Differs from Module Mode

Module modeComponent mode
Binary formatCore WASM moduleWASM Component Model
Function invocationcli_args: ["--invoke", "add"] + inputs: [10, 20]name: "add" + inputs: ["1", "2"]
Argument encodingPassed as CLI positional argsWAVE-encoded typed values
WIT interfaceNot requiredRequired
Build targetwasm32-wasip1 (tinygo / emcc)wasm32-wasip2 (cargo)

Invoking Directly with wasmtime

You can also test the component binary directly without propeller:

wasmtime run --invoke "add(1, 2)" target/wasm32-wasip2/release/add_component.wasm

Your output should look like this:

3

On this page