# How Easegress Supports WebAssembly for Custom Extensions: WasmHost Filter Architecture

> Easegress enables custom extensions with WebAssembly via the WasmHost filter. Execute Wasm modules for request processing and leverage host functions for HTTP, logging, and KV storage.

- Repository: [MegaEase/easegress](https://github.com/megaease/easegress)
- Tags: internals
- Published: 2026-03-07

---

**Easegress supports WebAssembly extensions through the `WasmHost` filter, which embeds a wasmtime-go runtime to execute Wasm modules for request processing while exposing host functions for HTTP context manipulation, logging, and distributed KV storage.**

Easegress treats WebAssembly (Wasm) as a first-class extension mechanism, allowing developers to write custom request-processing logic in any language that compiles to Wasm. When compiled with the `wasmhost` build tag, the server registers the `WasmHost` filter kind, enabling dynamic loading and execution of Wasm bytecode within a managed VM pool. This architecture isolates custom business logic from the proxy core while maintaining production performance through VM reuse, hot-reload capabilities, and deep integration with Easegress's distributed storage.

## Enabling WebAssembly Support at Build Time

To activate WebAssembly capabilities, compile Easegress with the `wasmhost` build tag. This conditional compilation includes the wasmtime-go runtime and registers the `WasmHost` filter type.

```bash
make build_server GOTAGS=wasmhost

```

For a complete build including client tools, use:

```bash
make wasm

```

According to the installation documentation in [`docs/01.Getting-Started/1.2.Install.md`](https://github.com/megaease/easegress/blob/main/docs/01.Getting-Started/1.2.Install.md), this tag is required because Wasm support is optional to keep binary sizes minimal for deployments that do not require custom extensions.

## WasmHost Filter Architecture

The WebAssembly integration in Easegress consists of several coordinated components that manage the full lifecycle of Wasm execution.

| Component | Role | Key Source File |
|-----------|------|-----------------|
| **WasmHost filter** | Manages filter specs, loads Wasm bytecode, watches for updates, and executes code for each request. | [`pkg/filters/wasmhost/wasmhost.go`](https://github.com/megaease/easegress/blob/main/pkg/filters/wasmhost/wasmhost.go) |
| **Wasm VM pool** | Reuses `wasmtime` virtual machines to avoid per-request VM creation overhead. | [`pkg/filters/wasmhost/vm.go`](https://github.com/megaease/easegress/blob/main/pkg/filters/wasmhost/vm.go) |
| **Host functions** | Exposes Go functions for request/response access, logging, and KV store operations via import objects. | [`pkg/filters/wasmhost/hostfunc.go`](https://github.com/megaease/easegress/blob/main/pkg/filters/wasmhost/hostfunc.go) |
| **Cluster integration** | Persists Wasm code and shared data in the Easegress KV store using dedicated paths (`/wasm/code` and `/wasm/data/...`). | [`pkg/cluster/layout.go`](https://github.com/megaease/easegress/blob/main/pkg/cluster/layout.go) |
| **HTTP API** | Provides admin endpoints for reloading code and managing shared data without server restarts. | [`pkg/api/wasm.go`](https://github.com/megaease/easegress/blob/main/pkg/api/wasm.go) |
| **CLI (`egctl`)** | Mirrors HTTP API functionality with sub-commands like `wasm reload-code` and `wasm apply-data`. | [`cmd/client/commandv2/wasm.go`](https://github.com/megaease/easegress/blob/main/cmd/client/commandv2/wasm.go) |

### Filter Specification and Initialization

In [`pkg/filters/wasmhost/wasmhost.go`](https://github.com/megaease/easegress/blob/main/pkg/filters/wasmhost/wasmhost.go), the `WasmHost` struct implements the filter interface. During pipeline initialization, the `Init()` method reads the `code` field—which accepts a file path, URL, or base64-encoded string—and loads the Wasm module into memory.

### VM Pool Lifecycle Management

The `NewWasmVMPool` function in [`pkg/filters/wasmhost/vm.go`](https://github.com/megaease/easegress/blob/main/pkg/filters/wasmhost/vm.go) creates a `wasmtime.Engine` and compiles the module once. It then instantiates a configurable pool of `WasmVM` instances based on the `MaxConcurrency` parameter, ensuring that request handling does not incur the overhead of VM creation per request.

## Request Processing Lifecycle

The execution flow for Wasm extensions follows six distinct phases:

1. **Initialization**: When a pipeline containing a `WasmHost` filter is created, `Init()` in [`pkg/filters/wasmhost/wasmhost.go`](https://github.com/megaease/easegress/blob/main/pkg/filters/wasmhost/wasmhost.go) validates the specification and loads the Wasm bytecode from the configured source.

2. **VM Pool Creation**: `NewWasmVMPool` initializes a `wasmtime.Engine`, compiles the Wasm module into machine code once, and pre-allocates VM instances. This pool approach minimizes latency by reusing VMs across requests.

3. **Request Handling**: For each request, the `Handle()` method obtains a VM from the pool, injects host functions via `importHostFuncs`, and passes the HTTP context (method, headers, body) along with **shared data** (key/value pairs from `/wasm/data/<pipeline>/<filter>/`) into the Wasm module. The runtime then calls the exported `wasm_run` function.

4. **Result Mapping**: The Wasm function returns an `int32` status code. The `wasmResultToFilterResult` function converts `0` to an empty string (indicating no jump) and positive integers to `wasmResultN` labels. These results drive conditional routing in pipeline `jumpIf` clauses.

5. **Dynamic Reload**: A background watcher monitors the KV path `/wasm/code`. When updated bytecode is detected, the `reload()` method discards the old VM pool and constructs a new one atomically, without dropping active connections or restarting the server.

6. **Shared Data Updates**: A second watcher monitors `/wasm/data/<pipeline>/<filter>/` for key/value changes. Updates are stored in the filter's internal `data` map and become immediately visible to subsequent Wasm executions, enabling dynamic configuration updates.

## Configuring WasmHost Filters

Define a WasmHost filter in your pipeline YAML by specifying the `code` source and timeout:

```yaml
name: wasm-pipeline
kind: Normal
filters:
  - filter: wasm
    name: wasm
    code: /home/megaease/example/build/optimized.wasm
    timeout: 100ms
    parameters:
      foo: bar

```

The `code` field supports absolute file paths, HTTP URLs, or base64-encoded Wasm binaries. Reference the complete specification in [`docs/07.Reference/7.02.Filters.md`](https://github.com/megaease/easegress/blob/main/docs/07.Reference/7.02.Filters.md).

## Building and Hot-Reloading Wasm Modules

Develop Wasm extensions in Rust, Go, or any compatible language. For Rust:

```bash
cargo build --target wasm32-unknown-unknown --release
cp target/wasm32-unknown-unknown/release/your_module.wasm /home/megaease/example/build/

```

Update running code without restarting:

```bash
cp new.wasm /home/megaease/example/build/optimized.wasm
egctl wasm reload-code -p wasm-pipeline -f wasm

```

This command invokes `POST /wasm/code` in [`pkg/api/wasm.go`](https://github.com/megaease/easegress/blob/main/pkg/api/wasm.go), triggering the internal `reload()` watcher.

## Shared Data Management

The WasmHost filter integrates with Easegress's distributed KV store to provide persistent state accessible to Wasm modules.

Set data via CLI:

```bash
echo 'counter: 100' | egctl wasm apply-data wasm-pipeline wasm --reload-code

```

List current data:

```bash
egctl wasm list-data wasm-pipeline wasm

```

Delete data:

```bash
egctl wasm delete-data wasm-pipeline wasm

```

These commands map to the HTTP API endpoints `GET/POST/DELETE /wasm/data/{pipeline}/{filter}` defined in [`pkg/api/wasm.go`](https://github.com/megaease/easegress/blob/main/pkg/api/wasm.go).

## Integrating Wasm Results with Pipeline Flow

Use the integer return value from `wasm_run` to control pipeline execution flow:

```yaml
filters:
  - filter: wasm
    name: wasm
    code: /home/megaease/example/build/optimized.wasm
  - filter: redirect
    name: redirect
    target: https://example.com
    jumpIf: { wasmResult1: END }

```

When the Wasm module returns `1`, Easegress maps this to `wasmResult1`, causing the pipeline to jump to the `END` phase and skip subsequent filters.

## Summary

- **Conditional Compilation**: WebAssembly support requires building Easegress with the `wasmhost` tag to include the wasmtime-go runtime.
- **VM Pool Architecture**: The `WasmHost` filter in [`pkg/filters/wasmhost/wasmhost.go`](https://github.com/megaease/easegress/blob/main/pkg/filters/wasmhost/wasmhost.go) manages a reusable pool of VMs to minimize per-request overhead.
- **Host Function Bridge**: [`pkg/filters/wasmhost/hostfunc.go`](https://github.com/megaease/easegress/blob/main/pkg/filters/wasmhost/hostfunc.go) exposes Go functions for HTTP context access, logging, and KV operations to Wasm modules.
- **Dynamic Lifecycle**: The `reload()` mechanism watches `/wasm/code` for updates, enabling hot-swapping of Wasm logic without service disruption.
- **Shared State**: The `/wasm/data/<pipeline>/<filter>/` path provides persistent key-value storage accessible across the cluster.
- **Pipeline Integration**: Wasm return codes map to `wasmResultN` labels for conditional `jumpIf` routing within pipelines.

## Frequently Asked Questions

### How do I enable WebAssembly support in Easegress?

Compile the server with the `wasmhost` build tag using `make build_server GOTAGS=wasmhost` or `make wasm` for a full binary. This includes the wasmtime-go runtime and registers the `WasmHost` filter type. Without this tag, Wasm functionality is excluded to reduce binary size.

### What languages can I use to write Wasm extensions?

Any language that compiles to WebAssembly. The Easegress documentation provides examples in Rust, but Go, AssemblyScript, C, and C++ are also compatible. The module must export a `wasm_run` function that returns an `int32` and imports host functions from the Easegress runtime.

### How does hot-reloading work without dropping requests?

Easegress maintains a background watcher on the `/wasm/code` KV path. When new bytecode is detected—via `egctl wasm reload-code` or direct API calls—the `reload()` method in [`pkg/filters/wasmhost/wasmhost.go`](https://github.com/megaease/easegress/blob/main/pkg/filters/wasmhost/wasmhost.go) atomically replaces the old VM pool with a new one. Existing requests complete using the old pool while new requests use the updated code.

### Can Wasm extensions access request headers and body?

Yes. Through the host functions defined in [`pkg/filters/wasmhost/hostfunc.go`](https://github.com/megaease/easegress/blob/main/pkg/filters/wasmhost/hostfunc.go), Wasm modules can read and modify HTTP request headers, body content, and response attributes. The `importHostFuncs` mechanism injects these capabilities into the VM instance before executing `wasm_run`.