# wasmCloud: a CNCF platform for running WebAssembly components on Kubernetes and at the edge

> wasmCloud is a CNCF Incubating project that runs deny-by-default WebAssembly components across clouds, Kubernetes clusters and edge nodes. This review covers the wash CLI, the wash-runtime host, the NATS-based control plane, and where the model stops fitting.

**wasmCloud/wasmCloud** — wasmCloud is an open source Cloud Native Computing Foundation (CNCF) project that enables teams to build, manage, and scale polyglot apps across any cloud, K8s, or edge.

- Repository: https://github.com/wasmCloud/wasmCloud
- Website: https://wasmcloud.com
- Stars: 2,444 · Forks: 261
- Language: Rust
- License: Apache-2.0
- Published: 2026-09-28 · Updated: 2026-09-28 · Language: en
- Canonical page: https://hysenlabs.com/projects/wasmcloud-wasmcloud

## The problem wasmCloud targets: container permissions are granted, not withheld

The README makes the argument directly: containers default to allow-by-default, so a container can reach the network, make system calls and read environment variables unless something blocks it. Locking one down means enumerating everything it might attempt and then enforcing that list from outside the process. WebAssembly components invert the default. A component can do nothing, no file I/O, no network access, no system calls, until a capability is explicitly granted, and the README states that capabilities are declared as language-agnostic interfaces inside the component itself.

The audience that follows from this is teams already operating distributed systems, not people looking for a general-purpose language runtime. The repository ships a Kubernetes operator, Helm charts, kind and k3s deploy assets, and a NATS-based control plane. If you are running a single process on a laptop, the platform layer is overhead you will not use. If you are running many small services and want the permission boundary to live in the artifact rather than in a pod security policy, the shape of the project makes sense.

## How wasmCloud works: operator, NATS control plane, and hosts running wash-runtime

The monorepo layout answers most of the architecture question. The Kubernetes operator in runtime-operator/ reconciles five custom resources: Host, Workload, WorkloadDeployment, WorkloadReplicaSet and Artifact. It schedules workloads onto host pods, and the protobuf definitions in proto/ describe the control-plane messages exchanged between the operator and hosts over NATS. So the operator is not the thing executing your code. It is a scheduler and reconciler that talks to a fleet of hosts through a message bus.

The host side is crates/wash-runtime, described as the embeddable Rust runtime that powers wash dev, the cluster host and custom embedded hosts. It wraps Wasmtime with a plugin-based capability model. That is the same runtime in your local development loop and in the cluster, which is the detail that matters most for debugging: a component that behaves under wash dev is running on the same engine the operator will schedule it onto.

One piece of the architecture is on its way out. The README marks runtime-gateway, an HTTP gateway that proxies traffic to host pods, as deprecated as of 2.0.3; routing is now handled by the operator via EndpointSlices on standard Kubernetes Services. The chart still installs the gateway by default for backwards compatibility, and you disable it with gateway.enabled: false. That default is the kind of thing that quietly shapes a deployment, because a team that installs the chart without reading this will run a proxy component the project no longer routes through.

## Installing wash and running a first component with wash dev

The CLI is called wash, and the README gives several install paths: a shell script, a PowerShell script, Homebrew, winget, or a cargo install from a clone. The Homebrew formula is the one that keeps the toolchain separate from the runtime:

```bash
brew install wasmcloud/wasmcloud/wash
wash -V
```

The second command should print the version. If it does not, the install path is wrong rather than the component, so check this before going further.

The quickstart has a prerequisite that is easy to miss: a Rust toolchain plus rustup target add wasm32-wasip2. Without that target, component builds will not produce something the host can run.

```bash
rustup target add wasm32-wasip2
```

Scaffolding pulls a template straight out of the repository rather than a registry, using --subfolder to select one of the entries under templates/:

```bash
wash new https://github.com/wasmCloud/wasmCloud.git \
  --subfolder templates/http-hello-world \
  --name hello
cd hello
wash dev
```

wash dev is a hot-reload development loop. In a second terminal, the README's example is a plain curl against port 8000, which should return the greeting string:

```bash
curl localhost:8000
```

The template list in the repository includes http-hello-world, http-handler, http-kv-handler and service-tcp, so the scaffolding step is not limited to an HTTP hello world. For the Kubernetes side, the README installs the operator and a bundled NATS from an OCI Helm chart, applying an overlay that disables the deprecated gateway:

```bash
helm install wasmcloud oci://ghcr.io/wasmcloud/charts/runtime-operator \
  --namespace wasmcloud --create-namespace \
  -f https://raw.githubusercontent.com/wasmCloud/wasmCloud/refs/heads/main/charts/runtime-operator/values.local.yaml
```

The repository's own Makefile offers a narrower local path, creating a kind cluster named wasmcloud from deploy/kind/kind-config.yaml and installing the chart into the wasmcloud-system namespace with values.local.yaml. Note that the Makefile's helm-install target does not pass the gateway overlay the README uses, so the two installation routes are not identical.

## Where the model breaks down: state, native dependencies, and a young operator

Deny-by-default cuts both ways. A component that needs a capability the host does not expose cannot work around it from inside the sandbox, and the README's own framing is that you decide exactly which interfaces each component can access while everything else is denied. If your service links a native library, shells out to a binary, or depends on a filesystem layout, the component model is the wrong container for it. The repository does include examples for persistent storage and a blobby example, so storage patterns exist, but they are explicit interfaces rather than ambient filesystem access.

The Kubernetes path carries its own costs. The operator reconciles five CRDs and communicates over NATS, so a working NATS deployment is part of your failure domain whether or not you think of yourself as running a message bus. The chart can bundle NATS, which removes one setup step but not the operational concept.

The Dockerfile is worth reading as a statement about maintenance risk. It builds wash on a rolling Chainguard Rust image and copies the binary into a separately rolling wolfi-base image, then runs wash --version as a smoke test in the final stage. The comment in the file explains why: the two images can sit on different glibc majors for a window, apk cannot reconcile the conflicting glibc packages, and without the smoke test the image builds green and fails later as a CrashLoopBackOff in the operator e2e cluster. That is a candid note, and it also tells you the container build depends on two independently moving base images. Pinning them is a decision you will have to make yourself; the README does not document rollback or version pinning for the chart.

## wasmCloud vs Spin and vs WasmEdge: different layers, not just different runtimes

The comparison that matters is about scope. Spin, from Fermyon, is a framework and runtime for building and running Wasm applications, with its own developer loop and its own hosting story. wasmCloud is a platform: the runtime is one crate in a monorepo that also contains a Kubernetes operator, CRDs, a Helm chart, protobuf control-plane definitions shared over NATS, and deploy assets for kind and k3s. Choosing wasmCloud means adopting the scheduling and messaging layer along with the execution engine. Choosing Spin means adopting an application framework and deciding separately how it gets scheduled.

WasmEdge answers a narrower question still. It is a standalone WebAssembly runtime, and it does not ship a Kubernetes operator or a NATS control plane. If what you want is to execute a module inside an existing process or a single host, a standalone runtime is the smaller dependency. If what you want is a fleet of hosts that a Kubernetes operator schedules components onto, you are in wasmCloud's territory and a standalone runtime leaves you building the control plane yourself.

The honest framing is that these are not interchangeable at the same layer. wasmCloud's own README positions the runtime as embeddable, which means it can be used the way a standalone runtime is used, but the project's center of gravity is the platform.

## Maintenance, release cadence, and what Apache-2.0 means for adopters

The repository is not archived, and the last push was on 2026-09-28. Releases have been frequent: v2.9.0 on 2026-09-08, v2.10.0 on 2026-09-23, and v2.10.1 on 2026-09-24. The workspace version in Cargo.toml is 2.10.1, matching the latest tag, and the workspace pins rust-version to 1.95.0 with edition 2024. That is a real constraint for anyone building from source: an older toolchain will not compile the workspace, and the lint configuration denies warnings, unsafe code, unwrap, expect and panic across the workspace, so a fork that relaxes those rules will diverge from upstream quickly.

Upgrade cost on the Kubernetes side is concentrated in the CRDs and the chart. The Makefile includes a helm-crds-check target that diffs runtime-operator/config/crd/bases against charts/runtime-operator/crds, which tells you the project treats those two copies as needing to stay in sync, and that a chart upgrade can move CRD definitions. The deprecated runtime-gateway is the other upgrade item: it is still installed by default, so teams that adopt the chart now and later set gateway.enabled: false are changing their routing path, not just a flag.

The licence is Apache-2.0, which is a permissive licence with an explicit patent grant. That is the standard choice for a CNCF project and it does not impose copyleft obligations on your components. This is a description of the licence identifier in the repository, not legal advice; review the LICENSE file and your own distribution model.

## Conclusion

Adopt wasmCloud when you already run Kubernetes, want component-level deny-by-default capability control, and are willing to take on a Rust toolchain, a NATS control plane and the Kubernetes operator. Do not adopt it if your workloads are ordinary Linux binaries with heavy native dependencies, or if you have no cluster and only need a single-process Wasm sandbox. Before committing, verify that the Helm chart with gateway.enabled: false matches your ingress setup, and check that your language toolchain emits wasm32-wasip2 components, since the quickstart requires rustup target add wasm32-wasip2.

## FAQ

### What is wasmCloud?

wasmCloud is a Cloud Native Computing Foundation Incubating project that runs WebAssembly components across clouds, Kubernetes, datacenters and edge nodes. It consists of the wash CLI, the wash-runtime host built on Wasmtime, and a Kubernetes operator that schedules workloads onto host pods over NATS.

### How does wasmCloud compare with WasmEdge?

WasmEdge is a standalone WebAssembly runtime, while wasmCloud ships a runtime plus a Kubernetes operator, CRDs, a Helm chart and protobuf control-plane messages carried over NATS. The README describes wash-runtime as embeddable, so it can be used like a standalone runtime, but the project's center of gravity is the platform layer.

### How do I install wasmCloud on Kubernetes?

The README installs the operator and a bundled NATS from an OCI Helm chart into a wasmcloud namespace, applying an overlay that disables the deprecated Runtime Gateway. The repository's Makefile also provides a kind-setup target that creates a cluster named wasmcloud from deploy/kind/kind-config.yaml.

### How do I run a wasmCloud component locally?

After installing wash and adding the wasm32-wasip2 Rust target, the quickstart scaffolds a component from templates/http-hello-world with wash new, then runs wash dev for a hot-reload development loop. A curl against localhost:8000 returns the template's greeting.

### Is the wasmCloud Runtime Gateway still required?

No. The README marks runtime-gateway as deprecated as of 2.0.3, with routing now handled by the operator via EndpointSlices on standard Kubernetes Services. The chart still installs it by default for backwards compatibility, and gateway.enabled: false skips it.

## Sources

- [License: Apache-2.0](https://github.com/wasmCloud/wasmCloud/blob/main/LICENSE)
- [Project website](https://wasmcloud.com)
- [README](https://github.com/wasmCloud/wasmCloud/blob/main/README.md)
- [Releases](https://github.com/wasmCloud/wasmCloud/releases)
- [wasmCloud/wasmCloud on GitHub](https://github.com/wasmCloud/wasmCloud)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/wasmcloud-wasmcloud
