Skip to content

WASI & syscalls

Compiled binaries from clang, and any wasm32-wasi module you bring, run on the Nimbus wasi_snapshot_preview1 host. 45 of the 46 preview1 functions work. The missing one is sock_accept, so WASM servers can’t take /port traffic yet. Preview1 has no sock_open, bind, or listen; an inbound-socket extension is designed but not shipped.

Blocking I/O uses JSPI. Socket calls and poll_oneoff are wrapped in WebAssembly.Suspending, and _start runs under WebAssembly.promising. This is feature-detected and has a fallback. Outbound TCP uses path_open('/dev/tcp/<host>/<port>') to open a real cloudflare:sockets connection. poll_oneoff can mix fd, clock, and socket subscriptions.

JSPI suspends a call; it cannot snapshot a stack. Programs that need fork or setjmp — bash above all — are additionally instrumented with Asyncify, which can unwind a running program’s call stack to memory and rewind it in another instance. The process fabric covers what that unlocked.

Smaller POSIX details are handled too. O_NOFOLLOW and O_APPEND work, symlinks survive path_rename, and read(2) on a socket fd goes to the socket. wasi-libc maps read to fd_read for every fd, so the host has to route it correctly.

Programs see NIMBUS_ABI=wasm32-wasi-nimbus. The in-session clang emits it, and the runtime catalog uses it to classify artifacts. WASM magic or a saved exec bit sends ./prog through the WASI runner with a pid and a process tab.

workerd blocks request-time WASM compilation from raw bytes. Modules must arrive pre-compiled in the module map. Pyodide extension packages must therefore be declared startup modules, while arbitrary dynamic loading fails with a clear diagnostic.

The remaining gaps are tracked with designs. WASI files still use snapshot-plus-diff-flush, which fits one-shots but not long-running processes. stdin is EOF. There are no inbound sockets. wasi-threads is refused at link time: a partial version could corrupt data, and the design note explains why.