WIT Reference

WIT (WebAssembly Interface Types) is the interface definition language of the WebAssembly Component Model. It describes the function signatures that components export and import.

Declaring accurate types matters for two reasons:

For JS components, Obelisk synthesizes WIT interfaces from the ffqn, params, and return_type fields in deployment.toml — no WIT files needed. Rust components define their own WIT files and use the bindgen! macro to generate bindings. See JS components and Rust components for details.

WIT identifiers must use kebab-case (e.g. sleep-millis, not sleep_millis).

WIT syntax

Package declaration

A WIT file begins with a package declaration giving the namespace and package name, optionally with a version:

package tutorial:activity;
// or with version:
package tutorial:activity@1.0.0;

The package name forms the first part of an interface's FFQN.

Interface and function declarations

An interface block groups related functions. Each function is declared with a name, parameter names and types, and a return type:

package tutorial:activity;

interface activity-sleepy {
    step: func(idx: u64, sleep-millis: u64) -> result<u64>;
    health-check: func() -> result;
}

World declaration

A world declares what a component exports (provides) and imports (depends on):

package any:any;

world any {
    export tutorial:activity/activity-sleepy;   // functions this component provides
    import obelisk:log/log@1.0.0;               // functions this component calls
}

Obelisk only inspects exported interfaces to identify the functions a component provides. The world's own package name and world name are ignored.

Named type declarations

Types like record, variant, enum, and flags can be named and reused across functions:

interface account {
    record user-info {
        login: string,
        id: u64,
    }

    enum status {
        active,
        suspended,
    }

    variant fetch-error {
        not-found,
        rate-limited(u32),   // payload: seconds until reset
    }

    get-user: func(login: string) -> result<user-info, fetch-error>;
    get-status: func(login: string) -> result<status>;
}

In deployment.toml for JS components, named types can also be written inline — Obelisk assigns generated names (t0, t1, …) automatically:

params = [
  { name = "point", type = "record { x: u32, y: u32 }" },
]
return_type = "result<variant { found(string), not-found }>"

Primitive types

WIT typeDescription
boolBoolean
u8Unsigned 8-bit integer
u16Unsigned 16-bit integer
u32Unsigned 32-bit integer
u64Unsigned 64-bit integer
s8Signed 8-bit integer
s16Signed 16-bit integer
s32Signed 32-bit integer
s64Signed 64-bit integer
f3232-bit float
f6464-bit float
charUnicode scalar value
stringUTF-8 string

Compound types

WIT syntaxDescription
option<T>Optional value
resultSuccess/failure with no payloads
result<T>Success with value, failure with no payload
result<_, E>Success with no payload, failure with error
result<T, E>Success with value, failure with error
list<T>Variable-length sequence
tuple<T1, T2, ...>Fixed-length heterogeneous sequence
record { field-name: T, ... }Object with named fields
variant { case-name(T), ... }Tagged union
enum { case-name, ... }Enumeration (one of a fixed set)
flags { flag-name, ... }Bit-flag set

JSON encoding

Arguments to obelisk.call and results are JSON-encoded. The mapping between WIT types and JSON:

WIT typeJSON encoding
booltrue / false
integers, floatsJSON number
char, stringJSON string
option<T> — someJSON value of T
option<T> — nonenull
result<T, E> — ok{"ok": <T value>}
result<T, E> — err{"err": <E value>}
result / result<T> — no payload{"ok": null} / {"err": null}
list<T>JSON array
tuple<T1, T2, ...>JSON array [val1, val2, ...]
record { field-name: T, ... }JSON object; kebab-case keys become snake_case: {"field_name": val}
variant { case-name(T) }No payload: "case_name". With payload: {"case_name": val}
enum { case-name }"case_name" (kebab-case → snake_case)
flags { flag-name }Array of active flag strings: ["flag_name"]

Note: kebab-case WIT identifiers become snake_case in JSON keys and values.

Numeric precision

JavaScript components return numbers as JSON numbers. Obelisk accepts numeric conversions between integer and floating-point WIT types only when the conversion is lossless:

For JavaScript Number, integers are exact only up to Number.MAX_SAFE_INTEGER (2^53 - 1). Use a string field when a JavaScript component needs to return larger integer identifiers without precision loss. f32 has a smaller precision range than f64, so some values that fit in f64 still cannot be returned for an f32 field without rounding.