Skip to main content
Version: v2

Interfaces

Interfaces are contracts that define the relationships between entities.

In wasmCloud, components communicate through interfaces, which come in two kinds:

  • Well-known interfaces are common standards (such as WebAssembly System Interface (WASI) APIs) or wasmCloud interfaces (core functionalities like wasmcloud:messaging) supported out-of-the-box by wasmCloud hosts.
  • Custom interfaces are user-created contracts that make it possible to extend and tailor how wasmCloud components and providers interact with one another.

In all cases, wasmCloud interfaces are defined using the interface description language WebAssembly Interface Type (WIT).

WebAssembly Interface Type (WIT)

WebAssembly Interface Type (WIT) is an open standard maintained as part of the Component Model by the W3C WebAssembly Community Group.

WIT enables WebAssembly components to define the functions they expose to external entities ("exports") and the functionalities they require ("imports") in .wit files.

Packages, namespaces, and versions

Interfaces defined in WIT are organized into packages. Packages must include a namespace and identifier.

Namespace and package in a WIT file

Optionally, WIT packages may include a version using semantic versioning.

Why 0.2.0-draft?

The version for the example above is 0.2.0-draft. WASI proposals move through three phases. Once a proposal reaches Phase 3, it may be included in the standard API group of WASI 0.2. The wasi-keyvalue interface above is at Phase 2.

In wasmCloud, you will often see packages belonging to the wasmcloud and wasi namespaces. You may also create custom interfaces with arbitrary namespaces. Packages with different namespaces may be mixed and matched freely, and the contents of a given package may be spread across multiple files.

A common organizational pattern divides a package into:

  • types.wit
  • imports.wit
  • world.wit
  • my-interface-name.wit

The packages an interface depends on are fetched into a deps folder next to the package's .wit files. wash resolves and fetches these for you; see Managing WIT dependencies.

Worlds

The highest-level contract in a WIT interface is called a world. A WIT world is akin to a complete description of a component, defining the imports and exports that enable the component to interact other entities. Here is a simple example of a world:

wit
package wasmcloud:demo;

world demo {
  import wasi:logging/logging;

  export wasi:http/incoming-handler@0.2.0;
}

This is the top-level world for a hypothetical component that imports on the logging interface from WASI Logging and exports (or exposes a function on) the incoming-handler interface from WASI HTTP. This enables the component to be invoked (and respond) via HTTP and to use logging functionality.

info

In addition to using the wasi:logging interface, logs printed to STDERR will be output in host logs by default.

There are often at least two worlds defined in a package. A common convention is to have an imports world and the world components typically target.

In a wasmCloud component project, it is conventional to include a top-level WIT world at the root of a wit folder in the project directory. For the recommended layout in projects with several components, see Project layout.

Interfaces

An interface is a collection of types and functions scoped to a package which can be used within a world. Interfaces are the only place that a type can be defined. Packages may contain multiple interfaces.

Interfaces represent the lower-level vocabulary of the contract between entities. Worlds may also refer to other worlds, which themselves may refer to interfaces or still "deeper" worlds. Here is the incoming-handler interface imported by the world above:

wit
/// This interface defines a handler of incoming HTTP Requests. It should
/// be exported by components which can respond to HTTP Requests.
interface incoming-handler {
  use types.{incoming-request, response-outparam};

  /// This function is invoked with an incoming HTTP Request, and a resource
  /// `response-outparam` which provides the capability to reply with an HTTP
  /// Response. The response is sent by calling the `response-outparam.set`
  /// method, which allows execution to continue after the response has been
  /// sent. This enables both streaming to the response body, and performing other
  /// work.
  ///
  /// The implementor of this function must write a response to the
  /// `response-outparam` before returning, or else the caller will respond
  /// with an error on its behalf.
  handle: func(
    request: incoming-request,
    response-out: response-outparam
  );
}

When two entities import and export respectively on the same interface (such as incoming-handler), they can be linked so that once invoked, they interact according to the contract defined in the interface.

Interface diagram

WIT without WebAssembly

In spite of the name, WIT isn't limited to WebAssembly: wasmCloud also uses WIT to define the interfaces used by providers and host functions written in Rust or Go. It is entirely possible, for example, to create a Rust or Go binary that uses WIT interfaces over the wRPC (WIT over RPC) protocol.

Well-known interfaces

wasmCloud supports interfaces belonging to WebAssembly System Interface (WASI) P2 (also known as WASI 0.2 / P2) in addition to a selection of interfaces proposed for inclusion in WASI, and interfaces belonging to the wasmCloud host.

The runtime has shipped WASI 0.3 (P3) support alongside P2 since 2.5.0, including wasi:http and wasi:cli at 0.3.0 and the P3 wasi:sockets interfaces, so components may target either P2 or P3 worlds. See WASI 0.3 in the Runtime section for the current P3 surface.

WASI interfaces

WASI P2 includes these APIs, all available for use with wasmCloud 2.0:

APIVersions
https://github.com/WebAssembly/wasi-io0.2.0
https://github.com/WebAssembly/wasi-clocks0.2.0
https://github.com/WebAssembly/wasi-random0.2.0
https://github.com/WebAssembly/wasi-filesystem*0.2.0
https://github.com/WebAssembly/wasi-sockets*0.2.0
https://github.com/WebAssembly/wasi-cli0.2.0
https://github.com/WebAssembly/wasi-http0.2.0
wasi-filesystem and wasi-sockets

wasi-filesystem access is granted through preopens. By default, components have no filesystem access. Directories can be explicitly mounted to a component via volume mounts in the workload manifest — see Filesystems and Volumes for details. wasi-virt can be used to embed a virtual filesystem directly into a component binary (for example, to bundle static assets).

wasi-sockets is supported with host-enforced policy: outbound TCP connections are allowed, services can bind on loopback, and DNS name resolution is denied by default. A workload can opt in to name resolution with a per-component allowedIpNameLookups allowlist (since 2.6.0; named allowIpNameLookup before 2.6.1), whose entries may be exact names, *.suffix wildcards, *, or literal IPs. The host enforces these restrictions unconditionally—components do not need to implement their own socket access control. For an overview of socket policy and the service model for intra-workload TCP, see Network Access and Socket Isolation.

Additionally, wasmCloud supports proposed WASI APIs that are in the process of implementation and standardization:

APIVersions
https://github.com/WebAssembly/wasi-blobstore0.2.0-draft
https://github.com/WebAssembly/wasi-config0.2.0-rc.1
https://github.com/WebAssembly/wasi-keyvalue0.2.0-draft
https://github.com/WebAssembly/wasi-logging0.1.0-draft
https://github.com/WebAssembly/wasi-otel0.2.0-rc.2
https://github.com/WebAssembly/wasi-tls0.3.0-draft
https://github.com/WebAssembly/wasi-webgpu0.3.0-rc.2

wasi:webgpu support ships in default wash-runtime builds via the wasi-webgpu Cargo feature, with the implementation provided by the wasi-gfx project. The runtime's registration is version-tolerant, so components built against earlier revisions of the proposal (such as 0.0.1) continue to bind; the proposal itself is early-stage and its WIT surface may change substantially.

wasi-tls

wasi:tls (since 2.2.0) lets components terminate TLS connections themselves over wasi:sockets using the WASI Preview 3 wasi:tls/client and wasi:tls/types interfaces. Support is opt-in via the wasi-tls Cargo feature on wash-runtime while the upstream WIT stabilizes. Embedders can register a custom TLS provider through EngineBuilder::with_tls_provider — see Building Custom Hosts for details.

wasmCloud interfaces

Well-known interfaces include seven APIs built specifically for wasmCloud:

APIVersionsInterfaces
wasmcloud:messaging0.2.0 (sync), 0.3.0 (async)consumer, handler, types
wasmcloud:keyvalue0.2.0store, atomics, batch, cas, watcher, types
wasmcloud:blobstore0.1.0blobstore, container, types
wasmcloud:nats0.1.0types, core, jetstream, kv, core-handler, jetstream-handler, kv-handler
wasmcloud:postgres0.1.1-draft (sync), 0.2.0 (async)query, prepared, types
wasmcloud:host0.1.4types, identity, cancel, workload-call, workload-lifecycle
wasmcloud:secrets2.1.0store, reveal, secret
  • wasmcloud:messaging facilitates communication through message brokers: consumer for publishing and request/reply, handler for receiving deliveries. The async 0.3.0 revision (since 2.8.0) adds an optional timeout-ms on request, typed error variants such as timeout and broker-unavailable, and a reject/retry/other disposition returned by handlers. The host currently logs the disposition; mapping retry to broker redelivery is left to future backend support. A service that exports handler@0.3.0 receives messages through the messaging ingress.
  • wasmcloud:keyvalue is the async-shaped key-value package, extending wasi:keyvalue with TTL on set, compare-and-swap, batch operations, and typed errors for missing keys, conflicts, and backend failures. The bucket resource and error types live in a shared types interface, so a labeled multi-backend store import can use cas, atomics, and batch against the same bucket. A watcher interface is defined in the package, but watch delivery is not yet implemented by the runtime plugin. Runtime support requires the wasm_component_model_implements Cargo feature, part of the default feature set and stock release images since wasmCloud 2.7.0. See Host Interfaces for details.
  • wasmcloud:blobstore is the async-shaped blob/object storage package, the streaming counterpart to wasi:blobstore. It uses the same shared-resource pattern through its container interface and carries the same wasm_component_model_implements requirement.
  • wasmcloud:nats (since 2.9.0) is the NATS-native package for workloads that need broker semantics wasmcloud:messaging deliberately abstracts away: JetStream streams with explicit acknowledgement and redelivery, compare-and-swap on key-value revisions, queue groups, and subject-level grants. Every operation that touches the wire is async, connections are made per workload under the workload's own credentials, and subjects, streams, and buckets are deny-by-default grants declared by the operator. See the Host Interface Configuration Reference.
  • wasmcloud:postgres provides direct PostgreSQL access (one-shot query, prepared statements, and shared types) in a sync (0.1.1-draft) and an async (0.2.0) shape, both served by the built-in Postgres host plugin.
  • wasmcloud:host lets host component plugins (and other components running as trigger services) observe and act on their runtime environment. It provides identity (the workload and component IDs of the current caller, for per-caller state partitioning), cancel (cooperative per-invocation cancellation), workload-call (since 2.7.0), which invokes interfaces that workloads export and reports failures as types.call-error values rather than traps, and the shared types as imports, plus workload-lifecycle (since 2.6.0), which a plugin can optionally export to observe workloads binding to and unbinding from it. The 0.1.4 revision (since 2.9.0) adds identity.get-binding-name, the implements label the current call arrived on.
  • wasmcloud:secrets defines opaque-handle access to a secrets backend: store looks up a secret as a borrowable resource, and reveal gates access to its value so a host can permit lookup and reveal independently. The package is async-shaped (since 2.6.0), which makes it servable by a host component plugin, and its labeled secret interface (one nullary get per labeled import) lets a plugin's own secrets resolve before instantiation. The runtime also ships a built-in wasmcloud:secrets plugin that delivers each component's secrets from deploy-time configuration (Kubernetes Secrets via secretFrom), isolated per component. A host component plugin remains the path for serving secrets from an external backend, typically provisioning per-workload secrets in a workload-lifecycle bind hook and partitioning access via wasmcloud:host/identity.

You may also encounter wasmcloud:runtime@0.1.0 in the wasmCloud source: it holds the runtime's own internal world definitions (the typed surfaces of the built-in host plugins), and is not an interface for components to import.

These packages are published as OCI artifacts to ghcr.io/wasmcloud/interfaces/ and indexed in the wasmcloud namespace on wasm.directory, a community-run meta-registry for WebAssembly packages. wash fetches them automatically when a world references them; see Managing WIT dependencies.

Sync and async revisions

Several wasmCloud packages come in two shapes. Sync revisions use plain functions and buffered payloads. Async revisions use async func, typed error variants, and streams where payloads can be large (stream<u8> message and object bodies, stream<row> query results). Async revisions depend on the component-model-async proposal implied by WASI 0.3, so building against them takes a bindings generator with async support, the same tooling used for WASI 0.3 components (wit-bindgen with its async features in Rust, componentize-go async worlds in Go).

  • wasmcloud:messaging (0.2.0 sync, 0.3.0 async since 2.8.0) and wasmcloud:postgres (0.1.1-draft sync, 0.2.0 async) ship both revisions.
  • wasmcloud:keyvalue and wasmcloud:blobstore (since 2.5.0) are async only; their sync counterparts are wasi:keyvalue and wasi:blobstore.
  • wasmcloud:secrets is served only in its async shape (since 2.6.0); the earlier sync 1.0.0 WIT was never served by the runtime.
  • wasmcloud:nats (since 2.9.0) is async only.

A component's WIT fixes which revision it imports, and the host interface entry has to match. The version on a host interface entry selects the revision the host links; an omitted version binds the sync revision (0.2.0 for messaging, 0.1.1-draft for postgres). For exports, the host invokes the revision the component exports, and a messaging component that exports both handlers is invoked at 0.3.0. Both revisions share the same backends and configuration. See the Host Interface Configuration Reference for each package's revisions and config keys.

Custom interfaces

WASI interfaces are ultimately common standards using WIT, but wasmCloud enables you to build custom WIT interfaces and communicate between components in the way best-suited to your requirements.

Here is an example of a greeter interface defined in WIT:

wit
package local:greeter-demo; // <namespace>:<package>

interface greet { // interface <name of interface>
  greet: func(name: string) -> string; // a function named "greet"
}

world greeter {
  export greet; // make the `greet` function available to other components/the runtime
}

While reading the spec is the best way to learn about WIT, it is also designed to be easy to understand at a glance. WASI interfaces written in WIT contain their own documentation and are useful to consult as examples.

To share a custom interface across repositories, publish it as a package to an OCI registry; while it is still under development, a consumer can point the dependency at a local directory instead. See Publishing your own interfaces and Local file references.

Compared to gRPC and Smithy...

While similar frameworks and languages like gRPC and Smithy are meant to perform over network boundaries, WIT is in-process, and performs at near-native speed.

Interface-driven development

Interface-driven development (IDD) is a development approach that focuses on defining what capabilities components require before the specifics of how you will meet those needs.

Systems developed using IDD—especially distributed systems—are loosely coupled, robust, and maintainable.