userland.run vs container2wasm
container2wasm converts a container image into a WebAssembly module: a CPU emulator boots a real Linux kernel, which starts the container. It is the closest relative of userland.run — both emulate a CPU to run unmodified binaries — but they emulate at different levels and target different jobs.
Last verified: · sources cited below
The short answer
- Choose container2wasm to run an existing container image (x86_64, riscv64 or AArch64) in the browser or a WASI runtime with minimal porting — a full Linux kernel,
runcand all. - Choose userland.run to build an app around in-browser execution: an SDK, a terminal component, in-tab dev-server previews, a signed app catalog, and fast non-emulated tiers for Node, wasm apps and sandboxed JS.
Side by side
| container2wasm | userland.run | |
|---|---|---|
| License | Apache-2.0 for the converter; generated images include third-party software under their own licenses (Bochs, TinyEMU, QEMU, Linux, …). [1] | Runtime: AGPL-3.0 or commercial UEL. SDK: MPL-2.0 or UEL. Source on GitHub. |
| How it works | Full-system emulation: Bochs (x86_64) or TinyEMU (RISC-V) boot Linux and run the container with runc; --to-js uses QEMU compiled to wasm with TCG JIT. [1] | User-mode RV64GC RISC-V emulator + Linux syscall layer in wasm, plus peer runners: Node on the host JS engine, a wasm32-wasip1 runner, a Boa JS sandbox. |
| Node.js | Whatever Node build the container image contains, running under CPU emulation. | Real Node.js v25.4.0 ELF on the emulator (fidelity), or nodert on the browser's JS engine (fast, with documented divergences). |
| Native binaries | Yes — arbitrary Linux binaries of the image's architecture; x86_64, riscv64 or AArch64 recommended. [1] | Yes — static riscv64 Linux ELF binaries (BusyBox, ripgrep, …) and wasm32-wasip1 apps. |
| Offline / self-hosting | Static files plus wasm; the examples serve them from a plain web server. [1] | Static files you host yourself. Catalog apps come from a signed CDN index (mirrorable via CdnOptions.baseUrl) and are cached in OPFS. |
| Pricing | None (open source). | Free under AGPL-3.0 / MPL-2.0. A commercial license (UEL) is available from And The Next GmbH for terms the open-source licenses don't provide. |
| Browsers | Example configs set COOP/COEP; the networking example is "tested only on Chrome". [1][2] | Cross-origin isolation (COOP/COEP, or the shipped service worker) + SharedArrayBuffer. This site's sample suite runs in Chromium; other engines are not in the published test matrix. |
| Networking | Browser: HTTP(S) via a Fetch-based proxy (CORS applies) or packets over WebSocket to a host-side c2w-net. No built-in in-browser preview of servers. [1] | Inbound: in-tab servers previewed via a service worker (/sw/<port>/). Outbound: HTTP through the host fetch (CORS applies; an optional self-hosted CORS proxy ships). |
| Status | "This is an experimental software." Latest release v0.8.4 (2026-03-16). [1][3] | Pre-1.0 and active — see the changelog. |
Where container2wasm is better
- Any image, any distro. A full kernel means glibc, dynamic linking,
/proc, init systems and the long tail of Linux behaviour simply work. - x86_64. Most published containers are x86_64; userland.run only runs
riscv64binaries. - Outside the browser. The same module runs in WASI runtimes such as wasmtime.
- JIT option. The QEMU-based
--to-jspath compiles guest code with TCG instead of interpreting each instruction.
Where userland.run is different
- No kernel to boot. User-mode emulation implements the Linux syscall interface directly, so there is no boot and the slim core is 2.46 MB; binaries are fetched on demand.
- Faster tiers when emulation isn't needed. Node on the host JS engine,
wasm32-wasip1apps on the browser's wasm engine and a Boa sandbox share the emulator's filesystem. - Built for embedding. A typed SDK, the
<nano-terminal>component and in-tab dev-server previews. - Signed app catalog. Tools are installed per app with signature and hash verification instead of baked into one image.
The trade-off is coverage: userland.run implements the syscalls its workloads need (the reference lists 87), while container2wasm runs the real Linux kernel. If your workload is a whole distribution, container2wasm is the safer bet.
FAQ
Can userland.run run a Docker image?
No. It runs individual static riscv64 Linux executables and catalog apps on its own syscall layer; there is no container runtime or guest kernel. container2wasm is built for images.
Which one is faster?
Neither project publishes a head-to-head benchmark. User-mode emulation avoids booting and emulating a kernel; container2wasm's QEMU path can JIT guest code. Measure your own workload.
Do both need cross-origin isolation?
container2wasm's browser examples are served with COOP/COEP headers; userland.run requires cross-origin isolation too, either through headers or its shipped service worker.
Sources
- container2wasm on GitHub — READMEgithub.com/container2wasm/container2wasm
- container2wasm — examplesgithub.com/container2wasm/container2wasm/tree/main/examples
- container2wasm — releasesgithub.com/container2wasm/container2wasm/releases
- userland-run/nano — README and LICENSE.mdgithub.com/userland-run/nano
- userland-run/sdk — @userland-run/nano-sdk READMEgithub.com/userland-run/sdk
All third-party facts were checked against these pages on 2026-10-11. Products change — if something here is out of date, please open an issue.