WASM Functions
Use function.wat for inline WebAssembly Text source and function.wasm for precompiled binaries.
Classification: function configuration reference. WAT blocks are small registry examples. Precompiled examples assume an external component build, a filesystem entry, exported methods matching the guest WIT, and a SHA-256 digest calculated from the exact binary. Real-looking sample hashes are illustrative.
Inline WAT Functions
Define a WAT function directly in _index.yaml:
entries:
- name: answer
kind: function.wat
source: |
(module
(func (export "answer") (result i32)
i32.const 42
)
)
wit: |
answer: func() -> s32;
method: answer
pool:
type: inline
For larger WAT sources, use a file reference:
- name: answer
kind: function.wat
source: file://answer.wat
wit: |
answer: func() -> s32;
method: answer
pool:
type: inline
WAT Configuration Fields
| Field | Required | Description |
|---|---|---|
source |
Yes | Inline WAT source or file:// reference |
method |
Yes | Exported function name to call |
wit |
No | WIT signature for raw/core modules |
pool |
No | Worker pool configuration |
transport |
No | Input/output mapping (default: payload) |
imports |
No | Host imports to enable (e.g., wasi:cli, wasi:io) |
wasi |
No | WASI configuration (args, env, mounts) |
options.limits |
No | Execution limits (limits remains a deprecated compatibility spelling) |
Precompiled WASM Functions
Load compiled .wasm binaries from a filesystem entry:
entries:
- name: assets
kind: fs.directory
directory: ./wasm
- name: compute
kind: function.wasm
fs: myns:assets
path: /compute.wasm
hash: sha256:292b796376f8b4cc360acf2ea6b82d1084871c3607a079f30b446da8e5c984a4
method: compute
pool:
type: lazy
max_size: 4
WASM Configuration Fields
| Field | Required | Description |
|---|---|---|
fs |
Yes | Filesystem entry ID containing the binary |
path |
Yes | Path to .wasm file within the filesystem |
hash |
Yes | SHA-256 hash for integrity verification (sha256:...) |
method |
Yes | Exported function name to call |
wit |
No | WIT signature for raw/core modules |
pool |
No | Worker pool configuration |
transport |
No | Input/output mapping (default: payload) |
imports |
No | Host imports to enable |
wasi |
No | WASI configuration |
options.limits |
No | Execution limits (limits remains a deprecated compatibility spelling) |
Worker Pools
Each WASM function uses a pool of pre-compiled instances. The pool type controls concurrency and resource usage.
| Type | Description |
|---|---|
inline |
Mutex-serialized. Synchronous and asyncified calls reuse one warm instance; retained-memory policy or an execution failure can trigger replacement. |
lazy |
Zero idle workers. Scales on demand up to max_size. |
static |
Fixed number of workers with request queue. |
adaptive |
Auto-scaling elastic pool. |
Pool Configuration
pool:
type: static
size: 4 # Total pool size
workers: 2 # Worker threads
buffer: 16 # Request queue buffer (default: workers * 64)
pool:
type: lazy
max_size: 8 # Maximum concurrent instances
pool:
type: adaptive
max_size: 16 # Upper scaling bound
The 100-worker default applies only to the implicitly selected pool (when no type is set). When you explicitly set type: lazy or type: adaptive without max_size, the default maximum is 16 workers.
Worker Classes and Core Affinity
Setting pool.worker_class routes the function to a dedicated pool of OS-thread-pinned workers instead of the shared pool types above (type is ignored when set; conventional name: wasm):
pool:
worker_class: wasm
workers: 8 # optional; defaults to reserved cores, else min(NumCPU, 4)
Core isolation is opted into per runtime in .wippy.yaml:
scheduler:
wasm_isolation:
enabled: true # default: false
reserved_cores: 2 # cores reserved for WASM pools (default: 1)
With isolation enabled, the actor scheduler and the pinned WASM pools run on disjoint CPU sets (sched_setaffinity, Linux only — other platforms size the pools but do not bind threads). Long-running WASM calls then cannot starve actor scheduling.
Transports
Transports control how input and output are mapped between the runtime and the WASM module.
| Transport | Description |
|---|---|
payload |
Maps runtime payloads directly to WASM call arguments (default) |
wasi-http |
Maps HTTP request/response context to WASM arguments and results |
Payload Transport
The default transport passes arguments directly. Lua values are transcoded to Go types, then lowered to WIT types:
- name: compute
kind: function.wasm
fs: myns:assets
path: /compute.wasm
hash: sha256:...
method: compute
pool:
type: inline
-- Arguments passed directly as WASM function parameters
local result, err = funcs.call("myns:compute", 6, 7)
if err then return nil, err end
-- result: 42
WASI HTTP Transport
The wasi-http transport maps HTTP requests to WASM and writes results back to the HTTP response. Use this to expose WASM functions as HTTP endpoints:
- name: greet_wasm
kind: function.wasm
fs: myns:assets
path: /greet.wasm
hash: sha256:...
method: greet
transport: wasi-http
pool:
type: inline
- name: greet_endpoint
kind: http.endpoint
meta:
router: myns:api
method: POST
path: /api/greet
func: greet_wasm
Execution Limits
The options.limits block bounds a function's execution time, its warm-worker memory, and the sockets it may open:
options:
limits:
max_execution_ms: 5000
max_retained_memory_bytes: 134217728
retained_memory_check_interval: 32
max_open_sockets: 8
socket_timeout_ms: 5000
| Field | Default | Description |
|---|---|---|
max_execution_ms |
unlimited | Wall-clock budget for one call. When exceeded, the execution is cancelled and an error is returned. |
max_retained_memory_bytes |
67108864 (64 MiB) |
Post-call recycling trigger. A warm worker whose linear memory exceeds this is retired after the call instead of being reused. An explicit 0 disables retained-memory recycling. |
retained_memory_check_interval |
16 with the built-in limit, every call with an explicit limit |
Number of calls between post-call memory inspections. |
max_open_sockets |
16 |
Concurrently open connections per instance for the socket host. |
socket_timeout_ms |
30000 |
Deadline for a socket dial and for each send/receive. |
Negative values are rejected at boot.
The root limits and meta.options.limits spellings are accepted temporarily
with a deprecation warning. Keep pool at the entry root; it has not moved
under options.
WASI Configuration
Configure WASI capabilities for the guest module:
wasi:
args: ["--verbose"]
cwd: "/app"
env:
- id: myns:api_key
name: API_KEY
required: true
- id: myns:debug_mode
name: DEBUG
mounts:
- fs: myns:data_files
guest: /data
read_only: true
- fs: myns:output
guest: /output
| Field | Description |
|---|---|
args |
Command-line arguments passed to the guest |
cwd |
Working directory inside the guest (must be absolute) |
env |
Environment variables mapped from registry env entries |
mounts |
Filesystem mounts from registry filesystem entries |
Environment variables are resolved from the environment registry at call time. Required variables cause an error if not found.
Mount paths must be absolute and unique. Each mount maps a runtime filesystem entry to a guest directory path.
Examples
Data Transformation Pipeline
entries:
- name: wasm_binaries
kind: fs.directory
directory: ./wasm
- name: transform_users
kind: function.wasm
fs: myns:wasm_binaries
path: /mapper.wasm
hash: sha256:7304fc7d19778605458ae5804dae9a7343dcd3f5fc22bcc9415e98b5047192dd
method: transform-users
pool:
type: lazy
max_size: 4
- name: filter_active
kind: function.wasm
fs: myns:wasm_binaries
path: /mapper.wasm
hash: sha256:7304fc7d19778605458ae5804dae9a7343dcd3f5fc22bcc9415e98b5047192dd
method: filter-active
pool:
type: lazy
max_size: 4
local funcs = require("funcs")
local users = {
{id = 1, name = "Alice", tags = {"admin", "dev"}, active = true},
{id = 2, name = "Bob", tags = {"user"}, active = false},
{id = 3, name = "Carol", tags = {"dev"}, active = true},
}
-- Transform: adds display field and tag count
local transformed, err = funcs.call("myns:transform_users", users)
if err then return nil, err end
-- Filter: returns only active users
local active, filter_err = funcs.call("myns:filter_active", users)
if filter_err then return nil, filter_err end
Async Sleep with WASI Clocks
WASM components that import wasi:clocks, wasi:io and wasi:poll can use clocks and polling. The async yield mechanism integrates with the Wippy dispatcher:
- name: sleep_ms
kind: function.wasm
fs: myns:wasm_binaries
path: /sleep_test.wasm
hash: sha256:...
method: "test-sleep#sleep-ms"
imports:
- wasi:io
- wasi:poll
- wasi:clocks
pool:
type: inline
The # separator in the method field references an interface method: test-sleep#sleep-ms calls the sleep-ms function from the test-sleep interface.
See Also
- Overview - WebAssembly runtime overview
- Host Functions - Available host interfaces
- Processes - Running WASM as processes
- Entry Kinds - All registry entry kinds