Skip to main content
Version: v2

Configuration

You can read runtime configuration values in a Rust component with the wasi:cli/environment interface. Configuration values can be supplied from inline key-value pairs, Kubernetes ConfigMaps, and Kubernetes Secrets. All arrive through the same interface regardless of source.

This guide walks through reading wasi:cli/environment from a Rust component and shows how to provide values via a Kubernetes workload manifest.

Overview

wasi:cli/environment is part of the standard WASI P2 suite and is always available in a wasmCloud host. It exposes a get-environment function that returns all configuration key-value pairs available to the component. In production, values come from localResources.environment in a Workload or WorkloadDeployment manifest, which accepts inline key-value pairs, Kubernetes ConfigMaps, and Kubernetes Secrets.

Guidance for operators

The Secrets and Configuration Management page in the Operator Manual describes how the Kubernetes operator injects values via wasi:cli/environment. This guide covers the component author's side: how to read those values in Rust.

wasi:cli/environment is provided by the wasip2 crate maintained by the Bytecode Alliance. wstd already depends on wasip2 internally, but does not re-export it publicly, so you add wasip2 as a direct dependency and call wasip2::cli::environment::get_environment from your handler. No wit-bindgen setup is required.

Step 1: Add the dependency

In Cargo.toml:

toml
[dependencies]
wasip2 = "1.0"
wstd = "0.6"

Step 2: Read configuration values

In src/lib.rs, add a helper that reads all key-value pairs into a HashMap for convenient lookup:

rust
use std::collections::HashMap;
use wstd::http::{Body, Request, Response};

fn load_config() -> HashMap<String, String> {
    wasip2::cli::environment::get_environment()
        .into_iter()
        .collect()
}

#[wstd::http_server]
async fn main(_req: Request<Body>) -> Result<Response<Body>, wstd::http::Error> {
    let config = load_config();

    let app_name = config
        .get("APP_NAME")
        .cloned()
        .unwrap_or_else(|| "My App (dev)".to_string());
    let upstream_url = config
        .get("UPSTREAM_URL")
        .cloned()
        .unwrap_or_else(|| "http://localhost:9090".to_string());

    let body = format!("app={app_name}\nupstream={upstream_url}\n");
    Ok(Response::new(Body::from(body)))
}

Call get_environment() (or your load_config helper) inside each request handler rather than at module scope. Configuration is stable for the lifetime of an invocation, but reading at module scope can run before the host has finished injecting values.

Synchronous API

get_environment is synchronous in WIT. It returns Vec<(String, String)> directly without an async wrapper. The call works the same way whether your handler is synchronous or asynchronous.

Step 3: Provide configuration values

In production (Kubernetes manifests)

All configuration values are delivered to the component through the localResources.environment field in a Workload or WorkloadDeployment manifest. Three sources are supported and can be combined.

Inline values

The simplest approach: provide key-value pairs directly in the manifest:

yaml
components:
  - name: http-component
    image: ghcr.io/your-org/your-component:latest
    localResources:
      environment:
        config:
          APP_NAME: My Service
          UPSTREAM_URL: https://api.example.com

Inline values are suitable for non-sensitive configuration that is safe to store in version control.

From a Kubernetes ConfigMap

Reference a ConfigMap by name. Each key in the ConfigMap becomes a configuration value in the component:

yaml
components:
  - name: http-component
    image: ghcr.io/your-org/your-component:latest
    localResources:
      environment:
        configFrom:
          - name: app-config

Create the ConfigMap separately:

yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  namespace: default
data:
  APP_NAME: My Service
  UPSTREAM_URL: https://api.example.com

From a Kubernetes Secret

Reference a Secret by name for sensitive values such as API keys or credentials:

yaml
components:
  - name: http-component
    image: ghcr.io/your-org/your-component:latest
    localResources:
      environment:
        secretFrom:
          - name: app-secrets

Secret values are delivered to the component as plain strings. No decoding is required in your component code.

Combining sources

All three sources can be used together. When the same key appears in multiple sources, the order of precedence (lowest to highest) is: configconfigFromsecretFrom.

yaml
apiVersion: runtime.wasmcloud.dev/v1alpha1
kind: WorkloadDeployment
metadata:
  name: my-app
  namespace: default
spec:
  replicas: 1
  template:
    spec:
      hostSelector:
        hostgroup: default
      components:
        - name: http-component
          image: ghcr.io/your-org/your-component:latest
          localResources:
            environment:
              config:
                APP_NAME: My Service           # inline (lowest precedence)
              configFrom:
                - name: app-config             # non-sensitive config from ConfigMap
              secretFrom:
                - name: app-secrets            # sensitive values from Secret (highest precedence)
      hostInterfaces:
        - namespace: wasi
          package: http
          interfaces:
            - incoming-handler
          config:
            host: my-app.example.com

The host: value is the HTTP Host header the wasmCloud host uses to route requests to this workload. If you want to override the listen address instead, use address: '0.0.0.0:8080'. See Secrets and Configuration Management for the full hostInterfaces reference.

tip

For a complete reference to localResources.environment fields, including precedence rules and RBAC considerations, see Secrets and Configuration Management.

During development (wash dev)

wash dev provides the wasi:cli/environment interface, but localResources.environment defaults to empty. There is currently no mechanism in .wash/config.yaml or the wash dev CLI to inject test configuration values into a component locally.

The practical approach for development is to supply fallback defaults in your component code, as shown in the example above. This lets your component run correctly during wash dev while reading real values in production.

Build and verify

shell
wash dev

wash dev builds the component and serves it on http://localhost:8000. With no configuration injected, your fallback defaults take effect:

shell
curl http://localhost:8000
text
app=My App (dev)
upstream=http://localhost:9090

To verify the import is correctly declared, inspect the built component:

shell
wasm-tools component wit target/wasm32-wasip2/release/<crate>.wasm | grep environment

You should see a line like import wasi:cli/environment@0.2.x. The exact patch version is governed by the wasip2 crate version that wstd resolves to.

Alternative: the wit-bindgen path

If you would rather not depend on wasip2 directly, you can declare the import in your WIT world and generate bindings with wit-bindgen.

In wit/world.wit:

wit
package wasmcloud:my-component;

world my-component {
  import wasi:cli/environment@0.2.2;

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

In src/lib.rs:

rust
mod bindings {
    wit_bindgen::generate!({ generate_all });
}

use bindings::wasi::cli::environment::get_environment;

let config: std::collections::HashMap<String, String> = get_environment().into_iter().collect();

The function name and signature are identical to the wasip2 crate path. Choose whichever fits your existing setup.

Summary: checklist for adding configuration

  1. Add wasip2 = "1.0" to Cargo.toml (or use wit-bindgen if you prefer to declare the import in your WIT world).
  2. Call wasip2::cli::environment::get_environment() inside request handlers, not at module scope.
  3. Collect into a HashMap for ergonomic key lookup: get_environment().into_iter().collect::<HashMap<_, _>>().
  4. Provide fallback defaults with unwrap_or_else for every value your component reads. This keeps the component functional during wash dev when no configuration is injected.
  5. In production, provide values via localResources.environment in your Kubernetes manifest, using config:, configFrom:, or secretFrom: as appropriate.

API reference: wasi:cli/environment functions

For the upstream WIT definitions, see the wasi:cli 0.2.x interfaces in the WebAssembly/wasi-cli repository.

FunctionSignatureDescription
get_environmentfn() -> Vec<(String, String)>Returns all configuration key-value pairs. Returns an empty Vec if no configuration has been provided to the component.
get_argumentsfn() -> Vec<String>Returns POSIX-style command-line arguments. Not used for configuration.
initial_cwdfn() -> Option<String>Returns the initial working directory. Not used for configuration.

Further reading