waclay: Runtime-Agnostic WebAssembly Component Layer in Rust
RustWebAssemblyWasmComponent ModelOpen SourceSystems

waclay is a lightweight, runtime-agnostic Rust library that implements a composition layer for the WebAssembly Component Model (WasmC). It helps you load, link and instantiate WebAssembly components across different backends β€” Wasmtime, Wasmer, browser runtimes and embedded hosts β€” while keeping your application code portable and backend-agnostic.

Why waclay?

The WebAssembly Component Model is changing how we think about Wasm: typed interfaces, component-level linking and cross-language bindings make Wasm a viable option for modular systems. However, tooling and runtime support for components are still maturing. That’s where waclay fits in:

  • Bridge the gap between components and runtimes: waclay provides an abstraction layer so you can write component composition code once and run it on different engines.
  • Reduce boilerplate: automatic interface-type resolution and linkage reduce repetitive wiring across runtimes.
  • Enable polyglot workflows: components written in different languages can be composed reliably using the same interface contracts.

What waclay provides

  • Parsing and interpreting component-model binaries (WasmC) from bytes or files.
  • Interface type resolution, import/export binding and instantiation abstractions.
  • A backend plugin model β€” plug in Wasmtime, Wasmer or another runtime and let waclay handle the component linking layer.
  • Extensibility hooks for future component-model changes.

Minimal example

The following Rust snippet demonstrates a minimal workflow: load two components, link them and call an exported function.

use waclay::{Engine, Store, Component, Linker};

// 1. Create an engine & store (runtime-specific, e.g., wasmtime)
let engine = Engine::new(/* options */)?;
let mut store = Store::new(&engine, ());

// 2. Load the component bytes
let comp_hello = Component::new(&engine, include_bytes!("hello.wasm"))?;
let comp_logger = Component::new(&engine, include_bytes!("logger.wasm"))?;

// 3. Create a linker and instantiate the first component
let mut linker = Linker::default();
let inst_hello = linker.instantiate(&mut store, &comp_hello)?;

// 4. Provide the `greet` export from hello to logger’s import
linker.instance(&mut store, &inst_hello)?;
let inst_logger = linker.instantiate(&mut store, &comp_logger)?;

// 5. Get the exported function and call it
let log_greeting = inst_logger
    .exports()
    .func("log_greeting")?
    .typed::<(), ()>()?;
log_greeting.call(&mut store, ())?;

This example highlights the key primitives: Component::new for loading, Linker for wiring imports/exports, and instantiate for creating runnable instances.

Real-world use-cases

  • Plugin systems: embed a safe sandbox and load user-written components at runtime.
  • Polyglot microservices: compose services authored in different languages via typed interfaces.
  • Embedded & edge: ship small, sandboxed component updates to devices.

Limitations & future work

  • The Wasm Component Model is evolving; waclay will need maintenance to track spec changes.
  • Performance-sensitive targets may prefer direct runtime integrations for maximal efficiency.
  • Better tooling for authoring WIT files and generating bindings remains an open area.

Getting started

  1. Add to your Cargo.toml:
waclay = "0.x"
  1. Check the GitHub repo: https://github.com/HemantKArya/waclay
  2. Build example components (e.g., cargo component or other toolchains) and try the minimal example.

Contributing

  • Test across backends and platforms.
  • Add more backend integrations (Wasmer, JsRuntime).
  • Improve docs and add tutorials for component authoring.

waclay is meant to be a forward-looking, developer-focused toolkit for working with Wasm components across runtimes. If this matches your needs, give it a spin and let me know how you adapt it.