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
- Add to your Cargo.toml:
waclay = "0.x"
- Check the GitHub repo: https://github.com/HemantKArya/waclay
- Build example components (e.g.,
cargo componentor 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.
