Skip to main content
Version: v2

Host Interface Configuration Reference

This page is the complete reference for the configuration keys each built-in host interface reads, as of wasmCloud 2.11.0. For the structure of the hostInterfaces field itself (namespace, package, interfaces, version, config, name, and multi-backend binding), see Host Interfaces in the CRD guide.

How configuration reaches an interface​

Each hostInterfaces entry carries a string-to-string config map assembled from up to three sources, later sources winning on key conflicts:

  1. The inline config map.
  2. ConfigMaps referenced by configFrom.
  3. Kubernetes Secrets referenced by secretFrom.

Some interfaces also read keys from the component's localResources.config, which is passed through as written. Where an interface reads from both, the tables below say so and give the precedence.

Three rules that apply across interfaces:

  • Named vs. unnamed entries bind differently. An entry with a name serves a labeled (implements ..) import and reads backend-selection keys (backend, url, and friends). An unnamed entry binds to the host's standalone plugin for that package, which on stock hosts means backend-selection keys on unnamed wasi:keyvalue, wasi:blobstore, and wasmcloud:messaging entries are ignored. Use a named entry (or the async wasmcloud:keyvalue/wasmcloud:blobstore packages) to select a backend per entry.
  • A labeled import never falls back silently to the default backend. A label is served by a matching named entry, by a plugin binding the operator declares in the host's plugins block (since 2.9.0), or by a sibling component whose components[].name matches (since 2.10.0; an operator-declared entry name wins over a same-named component). A label matching none of these fails the workload at start.
  • Backend addresses belong to the operator (since 2.11.0). Under the default workloadConfig: deny, the keys that say where a backend lives come only from the host's plugins declaration: url, root, and prefix for keyvalue, url and root for blobstore, url for messaging, and url for a named wasmcloud:postgres entry. A manifest that sets one is refused at deploy. The workload keeps backend, which says which kind of backend it wants. See Operator-owned backend addresses for the reasoning and the migration.

Operator-owned backend addresses​

Before 2.11.0 the multiplexed keyvalue, blobstore, messaging, and postgres plugins claimed no keys, so workloadConfig: deny had nothing to refuse on them and a workload manifest could name its own backend address. That let a workload point a filesystem backend at any directory the host could read, a redis or NATS backend at any server the host could reach, or a redis prefix at another workload's keyspace.

Since 2.11.0 each of those plugins declares its address keys host-owned:

Plugin idInterfaceKeys the operator owns
wasi-keyvalue-multiplexed, wasmcloud-keyvalue-multiplexedwasi:keyvalue, wasmcloud:keyvalueurl, root, prefix
wasi-blobstore-multiplexed, wasmcloud-blobstore-multiplexedwasi:blobstore, wasmcloud:blobstoreurl, root
wasmcloud-messaging-multiplexed, wasmcloud-messaging-async-multiplexedwasmcloud:messagingurl
wasmcloud-postgreswasmcloud:postgresurl (named entries); database is a ceiling

backend stays the workload's, so a manifest still chooses which kind of backend it wants while the operator says where that backend is. An operator who wants to pin the kind too adds backend to the entry's hostOwnedKeys.

This refuses existing manifests with no operator action

workloadConfig defaults to deny even when runtime.hostGroups[].plugins is empty, which is the chart default. A workload that sets root, url, or prefix on one of these entries is refused at deploy after upgrading, with a message naming the key:

it sets root, which belong to the operator; a manifest that set them could point itself at another backend or widen its own grant. Ask the operator to declare them under host.plugins

Set workloadConfig: warn on the plugin entry first to find affected workloads: it permits them and logs what deny would refuse.

The migration moves the address from the workload to the host group. A workload that previously carried its own root:

yaml
# Before 2.11.0 — refused under `deny` from 2.11.0 on
hostInterfaces:
  - name: cache
    namespace: wasi
    package: keyvalue
    interfaces: [store]
    config:
      backend: filesystem
      root: /data/cache

keeps only backend, and the operator declares the address:

yaml
# Workload
hostInterfaces:
  - name: cache
    namespace: wasi
    package: keyvalue
    interfaces: [store]
    config:
      backend: filesystem
yaml
# Helm values
runtime:
  hostGroups:
    - name: default
      plugins:
        - id: wasi-keyvalue-multiplexed
          bindings:
            cache:
              config:
                root: /data/cache

Declare the address under bindings.<label> rather than the entry's own config when workloads must stay apart: a root or prefix on the entry's config is shared by every workload binding that label, which is one store for all of them. Per-label bindings is what isolates them.

The alternative, where a workload legitimately owns its address, is workloadConfig: allow on that plugin entry paired with an allowedHosts ceiling: the workload names the url and the ceiling bounds which endpoints it may name. That pairing only works for a url-based backend — a filesystem backend's owned key is root, a path, which no allowedHosts ceiling bounds.

Plugin egress ceilings on multiplexed plugins​

Declaring allowedHosts on one of these plugin entries previously failed host startup, because the plugins did not report that they dial out. Since 2.11.0 all of them accept a ceiling, checked per backend at every bind, before any connection is reused:

wasi:keyvalue binding cache (backend 'redis') is refused by the egress policy declared for this plugin

The ceiling is one list per plugin entry; there is no per-binding allowedHosts. Three details matter when writing one:

  • Scheme aliases. postgres/postgresql, redis/valkey, and rediss/valkeys match as one scheme.
  • TLS upgrades are one-way. A plaintext entry also admits its TLS form at the same endpoint (nats:// admits tls://, redis:// admits rediss://), but a TLS entry never admits plaintext.
  • A port-less entry means the client's default port, not any port, when a native plugin dials it: redis 6379, postgres 5432, nats 4222. The same entry still leaves the port open for a workload's own raw sockets.

A url naming a hostname is matched by name only, because the plugin's own client resolves it. denySpecialRanges and denyPrivateRanges therefore constrain only a url that names a literal address. Credentials in a url are redacted from refusal messages.

wasi:http​

Serves wasi:http/incoming-handler (components) and wasi:http/handler (services). Keys are read from the wasi:http entry config:

KeyDescription
hostRouting hostname for the workload, matched against the request's Host header. Required on Kubernetes. Must be a bare RFC 1123 hostname without a port; matching ignores ports on both sides. Multiple workloads registered under the same hostname are load balanced per request.
host-aliasesComma-separated additional hostnames. Invalid entries are dropped silently. When spec.kubernetes.service is set, the operator replaces this key with the Service's in-cluster names (<svc>.<ns>, <svc>.<ns>.svc), so user-supplied aliases do not survive alongside a Service.
localRouteHostnames this workload serves for callers on the same host, comma-separated, as host or host/path (since 2.10.0). An invalid entry fails the workload at start.

There is no address key: the listen address and port are host-level settings (runtime.hostGroups[].http.port in Helm values, dev.address in wash configuration). Under wash dev, routing ignores hostnames entirely and sends every request to the current dev workload. The host normalizes scheme and authority before dispatch (since 2.10.0): a guest behind a TLS listener sees https, and a request with an invalid Host header is rejected with 400 before it reaches a component.

localRoute is the workload half of same-host local routing. Path prefixes match on / segment boundaries, the longest match wins, and scheme, port, and bare-path entries are rejected. Names declared here are never reachable from the network (a forged Host header from outside gets a 404); declare a name under host or host-aliases as well to serve it both ways. The key is inert unless the host runs with --http-local-routing, a caller must still list the hostname in its own allowedHosts, and gRPC requests always egress over the network. Under wash dev, valid entries are accepted and ignored (a dev session has one workload), but an invalid entry still fails the session, so a typo surfaces before deploy.

wasmcloud:messaging​

Serves consumer, handler, and types at 0.2.0 (sync) and 0.3.0 (async). The entry's version selects which revision is linked for imports; the handler revision follows the component's export. See Messaging subscriptions and consumer groups for the delivery model.

Keys are read from the component's localResources.config first; the NATS backend falls back to the wasmcloud:messaging entry config (the in-memory backend reads component config only):

KeyFormatDefaultOn invalid value
subscriptionsComma-separated NATS subjects; wildcards allowed (orders.*, audit.>)No subscriptions on the NATS backend. The in-memory backend used by wash dev delivers everything when unset.n/a
consumer_groupQueue group name, or the literal broadcast to deliver every message to every replica. No whitespace, *, or >.Derived group scoped to the workload's namespace, name, and componentWorkload fails to start
max_in_flightPositive integer; per-component in-flight delivery cap across replicas on a host (added in 2.8.0). Can only lower the component below the host's per-component ceiling.The host's per-component ceilingZero or invalid values are treated as unset, with a warning
admission_waitDuration (45s, 2m, 1m30s) or bare seconds; how long a delivery waits for a slot before it is dropped (added in 2.8.0). Maximum 600s.30sDefault, with a warning
admission_groupAny non-empty name; replaces the workload name in the admission gate's key, so same-named components in different workloads can share one gate (since 2.10.0)The stable replica identity the operator stamps, so replicas of one deployment share a gateEmpty or whitespace values are ignored

A named entry serving a labeled consumer import additionally reads:

KeyDescription
backendnats or in-memory. Default in-memory.
urlNATS server URL. Required when backend: nats; the workload fails to start without it. Since 2.11.0 this is the operator's to declare under the default workloadConfig: deny.

wasmcloud:nats​

Serves the async wasmcloud:nats@0.1.2 package (since 2.9.0 at 0.1.0; components built against an earlier 0.1.x keep binding; plugin id wasmcloud-nats): types; core (publish, request); jetstream (acknowledged publish, stored-message reads, pull consumers, stream and consumer info, subject listings); kv (open a bucket, then get, put, create, compare-and-swap update, delete, purge, keys, history, status, and select); and the handler exports the host drives (core-handler, jetstream-handler, kv-handler). kv.select (since 2.10.0) streams every matching entry with its value, uncapped, ending on a terminal-status future so a truncated drain is distinguishable from a complete one; its options cover tombstones, keys-only listing, an entry cap, and a whole-drain deadline. Key-value watching arrives through kv-handler and the kv-watches key, not a kv call. Every operation that touches the wire is async. Connections are opened per workload under the workload's own credentials, never the host's control plane client. Stream and bucket administration is absent by design: the host creates JetStream consumers for declared subscriptions, but streams and buckets are provisioned out of band.

Keys fall into three ownership classes, enforced by the plugin's declaration in the host's plugins block (workloadConfig: deny by default on Kubernetes). Spellings are canonicalized (case-insensitive, _ and - interchangeable) and unknown keys are refused. Configuration errors, unreachable servers, and out-of-grant subscriptions fail the deployment, not the first call.

Host-owned. Set only in the operator's declaration; a workload manifest that sets one is refused at deploy.

KeyDescription
serversNATS server URLs for the workload's connections. Defaults to the host's wasmcloudNatsUrl
nameConnection name reported to the server
jetstream-domainJetStream domain
inbox-prefixInbox prefix for request/reply
creds, jwt, nkey-seed, username, password, tokenCredentials (the aliases creds-file, nkey, and user are host-owned too)
tls-ca, tls-cert, tls-key, tls-firstTLS material and handshake order

Grant ceilings. The operator declares the maximum grant. A workload that omits the key takes the whole ceiling; one that sets the key may only narrow it, and setting a ceiling key the host never declared is refused. A ceiling nobody set denies everything. Reserved spaces ($JS.>, $SYS.>, $KV.>, $OBJ.>, _nats_push.>, and the host's own control subjects) stay denied even under a > grant; _INBOX is additionally reserved for subscriptions.

KeyGrants
subject-allowCore subjects the workload may publish and subscribe to
stream-allowJetStream streams the workload may read
bucket-allowKey-value buckets the workload may access

Workload-owned. Set in the entry's config or the component's localResources.config.

KeyFormatDefault
core-subscriptionssubject[:queue], comma-separatednone
jetstream-subscriptionsSTREAM:filter[:policy[:queue]], comma-separated. Policy is all, last, last-per-subject, or new (the default, which skips history)none
kv-watchesbucket[:filter], comma-separated; an omitted filter watches the whole bucketnone
componentWhich component of the workload receives dispatched handler callsthe workload's only component
ack-modeauto or manualauto
request-timeout-msMillisecondsunset
max-in-flightConcurrent deliveries to the workload64
max-ack-pendingJetStream unacknowledged-delivery capderived, floor 16
max-deliverDeliveries before a poison message is terminated (under ack-mode: auto); 0 means server-unlimited32
subscription-capacityBuffered messages per subscription1024
subscription-capacity-bytesBuffered bytes per subscription32 MiB

The entry supports named bindings, so a component can import wasmcloud:nats under two labels to bridge two clusters. The plugin's plugins declaration can also carry its own egress grants (allowedHosts, allowedIpNameLookups; since 2.10.0): declared servers endpoints are checked at startup and at bind, and cluster-discovered peers are not followed under a ceiling, so list every failover member. For choosing between packages: wasmcloud:messaging abstracts the broker away; wasmcloud:nats exposes NATS semantics, including explicit acknowledgement, redelivery, and revision-checked writes.

wasi:keyvalue and wasmcloud:keyvalue​

wasi:keyvalue serves store, atomics, and batch (sync); wasmcloud:keyvalue serves store, atomics, cas, and batch (async).

An unnamed wasi:keyvalue entry binds the host's standalone backend and reads no config keys: the bucket is whatever the guest passes to store.open(), and the backend endpoint is a host-level setting. Named entries (and all wasmcloud:keyvalue entries) select a backend per entry:

backendAdditional keysNotes
in-memory (default)noneIsolated per entry
redisurl (required), prefix (optional)Redis has a flat keyspace: the open() identifier does not namespace keys. prefix prepends a literal key prefix for isolation.
natsurl (required)JetStream key-value; the bucket named by open() must already exist
filesystemroot (required)Buckets are subdirectories of root

A missing required key fails the workload at start with an error naming the key. Since 2.11.0 url, root, and prefix are the operator's to declare under the default workloadConfig: deny, so on Kubernetes they belong on the plugin entry (per label, under bindings) rather than in the manifest. in-memory needs no address and so needs no declaration.

wasi:blobstore and wasmcloud:blobstore​

wasi:blobstore (sync) and wasmcloud:blobstore (async) serve blobstore, container, and types.

An unnamed wasi:blobstore entry binds the standalone NATS backend on a production host and reads:

KeyDescription
bucketsComma-separated allowlist of JetStream object store bucket names the workload may use. When empty or omitted, all container operations are denied, including create-container. Entries are matched exactly, without trimming whitespace.

The filesystem and in-memory backends used by wash dev read no keys and apply no allowlist, so a workload that works in the dev loop still needs buckets set for Kubernetes.

Named entries (and all wasmcloud:blobstore entries) select a backend per entry: in-memory (default), filesystem (requires root), or nats (requires url). Named entries do not read buckets. Since 2.11.0 root and url are the operator's to declare under the default workloadConfig: deny.

wasi:config​

Serves wasi:config/store. There are no fixed key names: the component's entire view is a merged map, later layers winning on conflicts:

  1. The workload's wasi:config entries in a stable order (unnamed first, then named), later entries winning; the host warns on conflicting keys (since 2.9.0).
  2. The component's localResources.config.
  3. The component's localResources.environment.

get and get-all expose exactly this merged map. Since 2.9.0 every component of the workload sees the same entry layer beneath its own localResources; before 2.9.0, a workload with several entries gave each component one arbitrary entry's config, varying between starts. Entries must all resolve to a single binding, so mixing a named and an unnamed wasi:config entry is refused at deploy. Under wash dev, the project's workload.config values are injected into the wasi:config entry automatically.

wasmcloud:secrets​

Serves store and reveal, plus labeled secret imports, at 2.1.0. Values are delivered from the entry's config, which on Kubernetes typically arrives via secretFrom. There are no fixed key names:

  • Unlabeled imports (store/reveal): the config maps of every unnamed wasmcloud:secrets entry are flattened into one per-component map, and store.get(key) looks keys up there. The same key set by two entries fails the workload at start.
  • Labeled imports (secret via (implements ..)): the entry's name doubles as the config key. The value at config[<name>] in that entry backs the label's get(). A label with no matching value fails the workload at start, naming the missing key.

See Workload Security for the delivery model and Interfaces for the package.

wasmcloud:postgres​

Serves query, prepared, and types at 0.1.1-draft (sync) and 0.2.0 (async); the entry's version selects the revision.

  • An unnamed entry requires the host to be started with a base connection URL (wash host --postgres-url or dev.postgres_url) and reads one key: database (required; the workload fails to start without it). Credentials, host, and TLS come from the host-level URL.
  • A named entry reads url (required): a full Postgres connection string. Since 2.11.0 this is the operator's to declare under the default workloadConfig: deny, per label under bindings.

Both URL forms honor two query parameters: pool_size (connection pool size, default 10) and sslmode (require, verify-ca, or verify-full to enable TLS).

Since 2.11.0 database on an unnamed entry is a grant ceiling rather than a free-form key: the operator lists the databases a workload may select, comma-separated, and the workload names one of them.

yaml
runtime:
  hostGroups:
    - name: default
      plugins:
        - id: wasmcloud-postgres
          config:
            database: app, reports

A deny host that serves the unnamed import must carry such a declaration — without one, a workload setting database is refused, because a grant the operator never declared cannot be narrowed into. A workload naming a database outside the ceiling is refused too, naming the value and the ceiling. When the ceiling lists several databases and the workload names none, the workload fails at start with a message listing them, since the host cannot choose on its behalf. A single-database ceiling is the simplest shape: the workload may then omit the key.

Separately from the database ceiling: when the plugin entry declares an allowedHosts ceiling, the host checks its own --postgres-url against it at startup, so a base URL outside the list fails host startup rather than being discovered at first query.

Interfaces with no configuration​

  • wasi:logging: structured logs flow to the host's logging pipeline; no keys.
  • wasi:otel: no per-workload keys. The host's own export is configured with standard OTEL_* environment variables and activates only when an endpoint variable is set (see Host telemetry); the plugin is active only on hosts started with --wasi-otel.
  • wasi:webgpu: no keys; active only on hosts started with --wasi-webgpu.
  • The WASI base (wasi:io, wasi:clocks, wasi:random, wasi:filesystem, wasi:sockets, wasi:cli) is always available and reads no hostInterfaces config. Where these are configurable at all it is through workload-level fields: the egress and loopback allowlists under component resource controls for wasi:sockets, and volumes for wasi:filesystem. wasi:io, wasi:clocks, wasi:random, and wasi:cli have no settings at all.
  • Since 2.11.0 a plugin can replace functions in a host-linked WASI interface — the base above plus wasi:http — for workloads that opt in. That is a custom-host capability rather than something a plugins entry can request.

wash dev differences​

The same keys apply to entries under dev.host_interfaces in wash configuration, with these differences:

  • Interfaces are also derived automatically from the component's own WIT imports, so most projects need no explicit entries.
  • HTTP routing ignores host, host-aliases, and localRoute.
  • Messaging keys are read from the component's config (workload.config merged with dev.components[].config), and the in-memory backend delivers all subjects when subscriptions is unset.
  • Secrets values come directly from entry config, with no Kubernetes Secret indirection.
  • wasmcloud:nats has no in-memory backend: under wash dev it connects to a real NATS server (the dev session's data NATS URL, nats://localhost:4222 by default), and workloadConfig defaults to allow in dev.