Component Model vs Core Modules
Flow-Like auto-detects whether a .wasm binary is a WebAssembly Component Model component or a core module. It adapts the binary’s ABI and exposes both as the same Flow-Like node abstraction.
Quick comparison
Section titled “Quick comparison”| Component Model | Core module | |
|---|---|---|
| Interface | WIT interfaces | Raw WebAssembly exports |
| Data exchange | Canonical ABI generated from WIT | JSON through linear memory |
| Export names | get-node, get-nodes, run, get-abi-version | get_node, get_nodes, run, optional get_abi_version |
| Memory handoff | Generated by component bindings | Packed pointer/length values; module alloc and dealloc are optional helpers |
| Direct TCP / UDP / DNS | Available through WASI networking when a network capability enables it | Not exposed |
| HTTP | WASI HTTP and Flow-Like host bridge, subject to capabilities | Flow-Like host bridge where the template SDK implements it |
| Format detection | Component header | Falls back to core-module loading |
| Flow-Like result | Node definitions and WasmExecutionResult | The same |
Component Model
Section titled “Component Model”The repository’s WIT world is flow-like:[email protected]. It imports Flow-Like interfaces for logging, pins, variables, cache, streaming, metadata, storage, models, authentication, HTTP, schemas, images, database operations, and WebSockets.
The component exports node definitions and execution results as strings containing JSON. Language bindings handle the canonical ABI representation, so package code does not manually pack pointers and lengths.
The runtime crate and Rust SDK currently declare numeric ABI version 2, while
several other maintained SDKs still emit 1. The loader records the reported
value but does not currently reject a binary solely because the number differs.
Use the value supplied by the language template rather than hard-coding the
Rust value. The numeric ABI is separate from the WIT package version.
Networking
Section titled “Networking”The component linker provides WASI Preview 2 and WASI HTTP interfaces.
Flow-Like host functions check their corresponding capabilities. The
component linker
enables TCP, UDP, and DNS lookup separately when their capabilities are granted;
the explicit allow_wasi_network override enables all three. Socket address
checks also apply the execution configuration’s host allowlist and block
server-side destinations covered by the execution environment’s egress policy.
The desktop loader for installed packages copies the manifest’s
allowed_hosts into the node’s execution configuration; the server executor
does not. The Flow-Like HTTP host function does not consult the list, so
enforce destination restrictions at the executor or network-policy layer.
An enabled network category is not blanket filesystem or process access.
Core modules
Section titled “Core modules”A core module exports:
| Export | Contract |
|---|---|
get_node() | Returns a packed pointer and length for one JSON definition |
get_nodes() | Returns a packed pointer and length for a JSON definition array |
run(ptr, len) | Reads execution-input JSON and returns result JSON |
alloc(size) | Optional module allocator |
dealloc(ptr, size) | Optional module deallocator |
get_abi_version() | Optional numeric ABI version |
At least one of get_node or get_nodes is required. When alloc is absent, the host uses its bounded allocator.
Core modules call flat Flow-Like host functions. They do not receive direct WASI socket access; network-capable core templates use the Flow-Like HTTP host bridge when their SDK supports it.
Language templates
Section titled “Language templates”The maintained formats are:
| Component Model | Toolchain |
|---|---|
| Rust | wasm32-wasip2 and wit-bindgen |
| Go | TinyGo and generated WIT bindings |
| C++ | wasi-sdk, wit-bindgen-c, and component wrapping |
| Zig | Zig, generated C bindings, and component wrapping |
| C# | .NET WASI tooling |
| Swift | SwiftWasm, generated C bindings, and component wrapping |
| Python | componentize-py |
| TypeScript | componentize-js |
| Core module | Toolchain |
|---|---|
| AssemblyScript | asc |
| Kotlin | Kotlin/Wasm with runtime GC and exception features enabled |
| Nim | Emscripten backend |
| Lua | Embedded Lua runtime compiled with Emscripten |
| Java | TeaVM |
| Grain | Native WASM output |
| MoonBit | Native WASM output |
The binary format does not guarantee identical SDK coverage. Check templates/wasm-capability-matrix.md before depending on a host function in a particular language.
Which model should you choose?
Section titled “Which model should you choose?”| Need | Choice |
|---|---|
| New package and a maintained Component Model template exists | Prefer the Component Model |
| Direct TCP, UDP, or DNS access | Component Model, with explicit permissions |
| Existing compatible core-module package | Keep the core module unless migration has a clear benefit |
| Language only has a maintained core template | Core module |
| Small computation-only node | Either; choose the better-supported template |
Do not wrap a core module as a component only to change the file header. A real migration requires WIT bindings and the component export contract.
Shared runtime behavior
Section titled “Shared runtime behavior”Both formats:
- run in Wasmtime;
- are cached by content and can use precompiled artifacts;
- receive node-specific capability configuration;
- are bounded by fuel, epoch interruption, memory, and timeout controls;
- produce the same node definitions, outputs, execution-pin activations, and error shape.
The ABI layer differs; the permission boundary and Flow-Like workflow model do not.
Upgrade the runtime and precompiled artifacts
Section titled “Upgrade the runtime and precompiled artifacts”Build the API, compilation workers, and executors with the same Wasmtime major
version. The workspace currently pins Wasmtime 48.0.1; use the repository’s
host Rust toolchain for those components. A worker rejects jobs
whose target key names another Wasmtime version, so a version 48 worker cannot
publish artifacts under a wt47 key.
Precompiled .cwasm artifacts from Wasmtime 47 cannot run on Wasmtime 48.
Registry and local cache platform keys derive their version from the workspace
dependency. Current keys include linux-x86_64-wt48 and ios-pulley64-wt48.
Source .wasm packages retain their node ABI and do not need to be rebuilt for
this runtime upgrade.
When deploying the upgrade:
- Coordinate the API, compiler, and executor rollout. If
EXECUTOR_PLATFORMis configured outside the repository, change its suffix towt48while retaining the executor’s operating system and architecture. - Request Linux artifacts for active packages with
POST /admin/packages/ensure-wasm-artifacts. Use the registry’s package recompilation operation for other required targets. - Wait for the required targets to finish compiling before routing runs to upgraded executors. The API requires the current target’s artifacts before dispatching a package.
Local caches discard incompatible artifacts and compile source Wasm again when
compilation is enabled. Executors can fall back to verified source Wasm when a
downloaded artifact cannot be deserialized. Deployments with compilation
disabled need matching wt48 artifacts in advance.
Wasmtime 48 denies TCP and UDP socket creation by default. The protocol grants described above enable permitted sockets; the HTTP host interfaces retain their separate capability checks. Upstream details are in the 48.0.0 release notes and 48.0.1 fixes.
Migration outline
Section titled “Migration outline”- Copy
flow-like-node.witinto the package’s WIT source. - Generate bindings using the destination language template.
- Implement the WIT exports instead of raw pointer/length exports.
- Replace flat host calls with generated interface calls.
- Build a real component and run the template’s interoperability tests.
- Publish it as a new package version and re-check all declared permissions.