WebAssembly Component Model Cheat Sheet [2026 WIT]
Bottom Line
Treat WIT as the contract and composition as interface matching, not symbol linking. Most real failures come from world shape, package-version drift, or unresolved imports you could have caught with one inspection command.
Key Takeaways
- ›A world is the full component contract; an interface is the reusable slice.
- ›wac plug is for simple one-way wiring; wac compose is for explicit multi-component graphs.
- ›wasm-tools component wit is the fastest way to spot import/export and version mismatches.
- ›wkg.toml local overrides plus wkg wit fetch keep WIT deps reproducible under
wit/deps. - ›wasm-tools component new --adapt bridges legacy
wasi_snapshot_preview1modules into components.
As of May 14, 2026, the practical WebAssembly Component Model workflow is clear: define contracts in WIT, generate bindings, inspect the resulting component boundary, and satisfy imports with WAC or a host Linker. This reference is optimized for recall, not theory. Use it when you need exact command shapes, quick reminders on world versus interface, and the linking patterns that usually break first in real projects.
- A world describes the complete import/export contract of a component.
- Package IDs use
namespace:name@version; version mismatches commonly block composition. - wac plug is asymmetric: a primary component imports, dependency components export.
- wasm-tools component wit is the first debugging command to reach for.
- Wasmtime runs, serves, and invokes components, but denies system access by default.
Command Quick Reference
Bottom Line
Think in four verbs: define, inspect, compose, and run. If imports do not line up at the interface level, no amount of host glue will save the composition.
Live Search Filter
Shortcuts: / focus filter, Esc clear, 1-5 jump sections.
Keyboard Shortcuts
| Shortcut | Action |
|---|---|
/ | Focus the live filter |
Esc | Clear the filter and show all command groups |
1 | Jump to Command Quick Reference |
2 | Jump to WIT Building Blocks |
3 | Jump to Linking Patterns |
4 | Jump to Configuration |
5 | Jump to Advanced Usage |
Install and Scaffold
cargo install cargo-component --locked
cargo install --locked wasm-tools
cargo install wkg
cargo install wasmtime-cli
cargo component new --lib hello-component
cargo component check
- cargo component new --lib scaffolds a library-style component; without --lib, it defaults to a command component.
- cargo component check is also the command the official docs recommend wiring into rust-analyzer.
Inspect and Validate
wasm-tools component wit component.wasm
wasm-tools validate component.wasm
wasm-tools print component.wasm
wasm-tools metadata show component.wasm
- Use component wit to view the embedded import/export contract.
- Use print when you need to confirm whether the artifact is a top-level
(component)or(module).
Compose and Link
wac plug validator-component.wasm --plug regex-component.wasm -o composed.wasm
wac compose \
--dep docs:regex-impl=regex-component.wasm \
--dep docs:validator-impl=validator-component.wasm \
-o composed.wasm \
composition.wac
- wac plug is the fast path when one primary component has a few direct imports.
- wac compose is the explicit path for named graphs and transitive dependencies.
Adapt Legacy WASIp1 Modules
wasm-tools component new my-core.wasm -o my-component.wasm \
--adapt wasi_snapshot_preview1.reactor.wasm
- Official adapter modules are published with Wasmtime releases.
- Choose the adapter by shape: command, reactor, or proxy.
Run, Serve, and Invoke
wasmtime run component.wasm
wasmtime serve http-proxy.wasm
wasmtime run --invoke 'add(1, 2)' add.wasm
jco run component.wasm arg1 arg2
- wasmtime run targets command components and can invoke typed exports with --invoke.
- wasmtime serve runs components implementing the
wasi:http/proxyworld.
WIT Building Blocks
Package, Interface, World
WIT is the IDL of the Component Model. Official docs define three core units: interfaces for focused functionality, worlds for a component’s full contract, and packages for organizing multiple .wit files.
package docs:validator@0.1.0;
interface validator {
validate-text: func(text: string) -> string;
}
world validator {
export validator;
import docs:regex/match@0.1.0;
}
- A world can import or export whole interfaces, and it can also import or export specific functions.
- A package ID must contain a
namespace:namepair and may include a semver version. - All files in the same WIT package use the
.witextension and live in one directory.
Reuse Patterns: use and include
Use smaller interfaces for stable building blocks, then aggregate them through worlds. This is the cleanest way to keep a large surface auditable. When you need tidy examples for docs or reviews, TechBytes’ Code Formatter is a practical companion for keeping WIT readable.
world glow-in-the-dark-multi-function-device {
include multi-function-device;
export glow: func(brightness: u8);
}
- include pulls another world’s imports and exports into the current world.
- Import and export operate at the interface level, not the package level.
Rich Types That Matter in Real Designs
resource blob {
constructor(init: list<u8>);
write: func(bytes: list<u8>);
read: func(n: u32) -> list<u8>;
merge: static func(lhs: blob, rhs: blob) -> blob;
}
record customer {
id: u64,
name: string,
picture: option<list<u8>>,
}
variant allowed-destinations {
none,
any,
restricted(list<string>),
}
- resource models external or non-copyable entities and supports constructors, methods, and static functions.
- option, result, record, and variant are the usual contract primitives for service-style components.
- Borrowing and ownership matter at the resource boundary even when the guest language hides the low-level details.
Linking Patterns
Pattern 1: Direct Interface Import
The simplest pattern is one component importing one interface from another package. The official Rust reuse guide shows this shape clearly.
package docs:calculator;
interface calculate {
eval-expression: func(expr: string) -> u32;
}
world calculator {
import docs:adder/add@0.1.0;
export calculate;
}
- Use this when you want a narrow dependency edge and a stable reusable interface.
- Keep imported interfaces focused; large worlds make downstream composition harder to reason about.
Pattern 2: Fast Build-Time Composition with wac plug
wac plug is asymmetric. A primary “socket” component imports functionality, and one or more dependency “plug” components export the matching interfaces.
wac plug path/to/component.wasm \
--plug path/to/dep1.wasm \
--plug path/to/dep2.wasm \
-o composed.wasm
- Good fit for application assembly and simple library wiring.
- The resulting component keeps the primary component’s exports, not the dependency exports.
Pattern 3: Explicit Graphs with wac compose
Once dependencies themselves have imports, the quick plug workflow stops scaling. Move to a .wac file and name each node deliberately.
// composition.wac
package docs:composition;
let regex = new docs:regex-impl { };
let validator = new docs:validator-impl { match: regex.match, ... };
export validator...;
wac compose --dep docs:regex-impl=regex-component.wasm \
--dep docs:validator-impl=validator-component.wasm \
-o composed.wasm \
composition.wac
- Use this when you need transitive dependency control or a composition that should be reviewed like source code.
- The interface contract is still the real linker input; filenames are just bindings for the composition step.
Pattern 4: Runtime Linking in the Host
Not every dependency should be flattened at build time. The Wasmtime component API documents the other common pattern: a Component becomes an Instance through a Linker. Use host-side linking when the environment, not another packaged component, should satisfy the import.
- Good fit for capabilities like filesystem access, environment injection, clocks, networking, or policy-controlled platform services.
- Prefer build-time composition for portable app bundles; prefer host linking for platform-owned capabilities.
Configuration
Resolve Local WIT Dependencies with wkg.toml
[overrides]
"docs:adder" = { path = "../adder/wit" }
wkg wit fetch
- Official docs show wkg wit fetch materializing dependencies under
wit/deps. - This is the lowest-friction way to keep local component contracts reproducible during development.
Rust Analyzer Setup
{
"rust-analyzer.check.overrideCommand": [
"cargo",
"component",
"check",
"--workspace",
"--all-targets",
"--message-format=json"
]
}
- The cargo-component README recommends overriding the check command so generated bindings stay in sync.
- cargo component new can write VS Code settings automatically unless you pass --editor none.
Wasmtime CLI Config Files
[optimize]
opt-level = 0
wasmtime compile --config config.toml
- Wasmtime supports TOML-based configuration for the same families of options exposed through --optimize, --codegen, --debug, --wasm, and --wasi.
- CLI flags override TOML settings when both are present.
Advanced Usage
Inspect First, Then Fix
wasm-tools component wit composed.wasm
wasm-tools print composed.wasm
wasm-tools validate composed.wasm
- If versions differ, inspect the embedded WIT instead of guessing from source directories.
- If you need to distinguish a core module from a component quickly, wasm-tools print exposes the top-level
(module)or(component).
Adapt Preview 1 Modules Deliberately
The wit-bindgen README explains the current bridge clearly: many native toolchains still emit wasm32-wasip1 core modules, then wasm-tools component new --adapt lifts them into component-model binaries.
- Use the command adapter for CLI-style entry points.
- Use the reactor adapter for library or event-driven shapes without a
main. - Use the proxy adapter for HTTP-serving flows.
JavaScript Workflow: Componentize, Inspect, Transpile
npx jco componentize \
string-reverse-upper.mjs \
--wit wit/ \
--world-name revup \
--out string-reverse-upper.incomplete.wasm \
--disable=all
npx jco wit string-reverse-upper.incomplete.wasm
npx jco transpile string-reverse-upper.wasm -o dist/transpiled
- The official JavaScript guide uses this flow to build a component, confirm unsatisfied imports, then inspect the completed component after composition.
- jco run is convenient, but official docs warn that its WASI implementation grants full access to the underlying system resources.
ldd, nm, and interface docs rolled into one. It is the shortest path from a failing composition to the actual contract mismatch.2026 Reality Check
- cargo component still describes itself as experimental and not stable in terms of the code it supports building.
- wasm-tools compose is marked deprecated in the official README; prefer WAC for composition.
- Wasmtime’s official component docs note that older versions may still require --wasm component-model when running a component.
Official Docs Worth Bookmarking
Frequently Asked Questions
What is the difference between a WIT interface and a WIT world? +
When should I use wac plug instead of wac compose? +
How do I debug a component version mismatch? +
namespace:name@version shape on both the import and export sides.Can I turn a wasisnapshotpreview1 module into a component? +
Get Engineering Deep-Dives in Your Inbox
Weekly breakdowns of architecture, security, and developer tooling — no fluff.
Related Deep-Dives
Wasm Component Model in 2026: Cloud Interop [Deep Dive]
A wider architecture view on where component portability is real and where platform differences still matter.
System ArchitectureWASM Component Model [Deep Dive] for Polyglot Systems
A higher-level systems guide to WIT, the Canonical ABI, and cross-language integration strategy.
Developer ReferenceWasm Components: Production Polyglot Microservices
A production-focused look at where components fit best once the reference patterns in this cheat sheet are working.