WASI, the WebAssembly System Interface, is what lets a Wasm module read a file, check the clock, or open a socket without being compiled against Linux, Windows, or any particular operating system. Wasm on its own is just a sandboxed instruction set with no I/O — it cannot open a file or make a network call unless the host explicitly gives it a way to. WASI is that way: a standardized set of interfaces that any host (a CLI runtime, an edge platform, a plugin system) can implement, so the same compiled module runs unmodified everywhere that interface exists.
What changed in 2026
- Preview 2 is the default target. The component-model-based
wasi 0.2 interface, built on WIT (WebAssembly Interface Types), has replaced wasi_snapshot_preview1 as what new tooling targets by default in Wasmtime, cargo component, and jco.
- Async support landed. WASI 0.3 brings native async to the component model itself, instead of every language faking it with callbacks or polling loops bolted onto a synchronous ABI.
- wasi-http and wasi-nn stabilized enough to build on. Standardized HTTP client/server interfaces and neural-network inference bindings mean edge functions and inference workloads no longer need host-specific glue code.
- The Bytecode Alliance runtimes converged on the same subsystems. Wasmtime, WasmEdge, and Wasmer all implement the same WASI proposals, so portability claims now mostly hold in practice, not just on paper.
- Plugin ecosystems kept growing. Envoy's Wasm filters, Shopify Functions, and Figma's plugin sandbox all rely on WASI-flavored capability models for safely running third-party code.
How the interface actually works
A Wasm module never gets ambient access to your filesystem or network — that is the entire point. Instead, the host decides at instantiation time what the module is allowed to touch, and passes in only those capabilities:
// Host side (Rust, using wasmtime + wasi-common)
let mut wasi_ctx = WasiCtxBuilder::new()
.preopened_dir(dir, "/data", DirPerms::READ, FilePerms::READ)?
.inherit_stdio()
.build();
The guest module only sees a preopened directory called /data, with read-only permissions — nothing else on disk exists from its point of view. This is capability-based security: instead of the OS checking permissions after the fact (like POSIX file permissions), the module simply has no handle to anything it was not explicitly given. There is no ambient authority to escalate.
The component model builds on top of this with WIT files that describe typed interfaces:
world http-handler {
import wasi:http/outgoing-handler@0.2.0;
export wasi:http/incoming-handler@0.2.0;
}
A "world" declares what a component imports and exports. Because the interface is typed and language-neutral, a component written in Rust can call one written in Python or JavaScript through the same ABI, with the canonical ABI handling the marshaling.
WASI Preview 1 vs Preview 2
| Aspect |
Preview 1 (wasi_snapshot_preview1) |
Preview 2 (wasi 0.2, component model) |
| Interface style |
POSIX-like flat syscalls |
Typed interfaces defined in WIT |
| Composability |
Modules only, no standard linking |
Components compose across languages |
| Async |
Not supported natively |
Native async arriving in WASI 0.3 |
| Tooling |
wasm32-wasi target |
wasm32-wasip2, cargo component, jco |
| Status in 2026 |
Legacy, still widely deployed |
Default target for new tooling |
Most production workloads still run a mix of both, since a large body of existing modules were built against Preview 1 and migrating means recompiling against the new target — it is not just a config flag.
Common mistakes
Assuming WASI means "sandboxed by default" without checking grants. A module preopened with a writable root directory has effectively the same access as a native process. Capability security only works if hosts actually scope grants narrowly.
Mixing Preview 1 and Preview 2 tooling in one build. Linkers and adapters exist to bridge them, but treating the two ABIs as interchangeable produces confusing runtime errors about missing imports.
Ignoring startup cost in latency-sensitive paths. Instantiating a module and wiring up its WASI context has overhead; for edge functions handling one request per instantiation, pooling and instance reuse matter more than raw execution speed.
Picking a runtime before checking WASI proposal support. Wasmtime, WasmEdge, and Wasmer do not all implement every proposal (wasi-nn, wasi-keyvalue, wasi-blobstore) at the same maturity level — verify before committing an architecture to one.
FAQ
Is WASI only for edge computing?
No. It is also used for plugin systems (Envoy, Shopify Functions), portable CLI tools, and sandboxed execution of untrusted code in CI pipelines.
Does WASI replace Docker or containers?
Not generally. WASI modules start faster and have a smaller footprint, but container ecosystems have broader OS compatibility and existing tooling. Many platforms run Wasm modules inside container orchestration rather than instead of it.
Do I need to rewrite my app to use WASI?
No. Languages with Wasm backends (Rust, Go via TinyGo, C/C++ via wasi-sdk) compile existing code to a WASI target; you generally do not hand-write WASI calls.
What is the component model, concretely?
A packaging and linking format on top of core Wasm that lets independently compiled components interoperate through typed WIT interfaces, instead of requiring all code to be compiled into one flat module.
Where to go next