Wasm vs. Docker: A Different Kind of Isolation
Docker revolutionised how software is packaged and deployed. WebAssembly rethinks what isolation means at a more fundamental level. This is not an upgrade — it is a different model.
Docker Changed Everything
Before Docker, deploying software meant managing dependencies by hand, reasoning about what was installed on the target machine, and hoping the environment matched what you had tested against. Docker solved this elegantly: package everything the application needs into an image, run it in a container, and get consistent behaviour everywhere.
That model has served the industry well for over a decade. Containers are now the default unit of deployment for most cloud-native software.
But Docker was designed around a specific problem — environment reproducibility — and its isolation model reflects that. WebAssembly was designed around a different problem entirely, and understanding the difference matters more as security and portability requirements grow stricter.
What Docker Actually Isolates
A Docker container isolates a process using Linux kernel primitives: namespaces for visibility (the container cannot see other containers’ processes or files) and cgroups for resource limits (CPU, memory). The process inside the container runs native machine code, on the real CPU, through the real kernel.
This is efficient and mature. It is also the source of Docker’s fundamental security limitation.
Because the container shares the host kernel, a kernel vulnerability or a container escape gives an attacker access to the host. The isolation is real but shallow — it is a boundary enforced by the operating system, not by the execution model itself. Containers can be configured more strictly, but the default is permissive: network access, filesystem access, and system calls are available unless explicitly restricted.
The security model is opt-out. You have to know what to remove.
What WebAssembly Isolates
A WebAssembly module does not run native code. It runs inside a virtual machine that executes a well-defined instruction set — one that has no concept of files, networks, processes, or system calls by default. The host (the Wasm runtime) decides what capabilities to expose to the module, explicitly, at startup.
This is the capability model: nothing is accessible unless it has been granted. A module that needs to write to a specific directory gets a handle to that directory — not access to the filesystem. A module that needs to make outbound HTTP requests gets a permission for that — not general network access. A vulnerability in the module cannot reach anything it was not explicitly given.
The security model is opt-in. You have to know what to add.
This distinction sounds subtle. In practice it means that in a Docker environment, a compromised container is a foothold into the host. In a Wasm environment, a compromised module is contained within exactly the capabilities it was granted — which are narrow by design.
WASI: System Access Without Ambient Authority
WASI (the WebAssembly System Interface) is the standard that defines how Wasm modules request access to system resources — files, clocks, environment variables, network sockets. It is explicitly capability-based: you do not get access to /tmp by being a running process. You get access to a specific directory handle, if the host grants it.
This matters for multi-tenant and shared-infrastructure environments. When multiple modules from different teams or different applications run on the same host, WASI ensures that the isolation between them is enforced at the instruction level, not just at the process level. There is no /proc to inspect, no shared memory to read, no syscall interface to exploit.
WASI also makes Wasm genuinely portable in a way Docker is not. A Docker image built for amd64 cannot run on arm64 without a separate build. A Wasm module compiled once runs identically on any CPU architecture, any operating system, any environment that has a Wasm runtime — including the browser, the edge, an embedded device, or a standard server. The module does not know or care what is underneath it.
Component Interfaces: Communication Without Networking
This is where WebAssembly diverges from the container model most significantly.
In Docker, services communicate over the network. They expose HTTP endpoints, speak gRPC, publish to message queues. All of this requires serialisation: turning data structures into bytes, sending them over TCP, deserialising on the other side. It requires service discovery. It requires a network stack. It introduces latency, failure modes, and security surface at every boundary.
The WebAssembly Component Model takes a different approach. Components define their interfaces using WIT (WebAssembly Interface Types) — a typed interface definition language that describes what a component exports and what it imports. When one component depends on another, the runtime links them directly: the function call crosses the boundary without going through a network, without serialising to bytes, without any of the overhead that comes with service-to-service communication.
interface document-store {
record document {
id: string,
content: string,
}
get: func(id: string) -> option<document>;
save: func(doc: document) -> result<_, string>;
}
This interface is the contract. The implementation can change — the language it is written in, the internal data model, the algorithms — without affecting anything that depends on it. The boundary is defined by the type system, not by an HTTP spec or a protobuf schema that has to be maintained separately.
Compared to the alternative — two Docker containers talking over HTTP — this is:
- Faster: no serialisation, no network hop, no connection overhead.
- Safer: the boundary is enforced by the runtime, not by correct HTTP handling on both sides.
- More explicit: what a component can access is declared in the interface, not inferred from what port it is listening on.
- Versionable: interface changes are breaking changes that the type system catches at link time, not at runtime.
The Practical Differences
| Docker | WebAssembly | |
|---|---|---|
| Isolation level | Kernel (namespace + cgroup) | Instruction set (sandbox) |
| Default security | Permissive, opt-out | Deny-by-default, opt-in |
| Portability | Per-architecture image | Single binary, any arch |
| Cold start | Seconds | Milliseconds |
| Module size | Tens of MB to GB | Tens of KB to low MB |
| Service communication | Network (HTTP/gRPC/etc.) | Direct typed function calls |
| Interface contract | Implicit (OpenAPI, protobuf) | Explicit (WIT) |
| Host kernel required | Yes | No |
When Docker Is Still the Right Tool
Docker is not going away. It is a mature, well-understood technology with a vast ecosystem, and for many use cases — particularly packaging existing applications or running software that was never designed for Wasm — it remains the practical choice.
The tooling around Wasm components is still maturing. Language support varies. The component model is newer and less widely adopted than the container model. Teams evaluating Wasm today are working with a technology that is production-capable but not yet as operationally familiar as containers.
What the Model Shift Means
The shift from containers to Wasm components is not primarily about performance. It is about what becomes possible when isolation is a first-class property of the execution model rather than something you configure on top of it.
When modules are isolated by design, security policies become platform concerns rather than application concerns. When interfaces are typed and explicit, the platform can generate accurate architecture diagrams, validate dependencies, and enforce contracts at link time. When communication is direct rather than networked, the overhead of service decomposition drops — making it practical to build much more modular software without paying a performance penalty.
These are not incremental improvements to the container model. They are what becomes available when you start from a different foundation.
Want to follow our progress?
We're onboarding early design partners and sharing what we learn.
Get Early Access