Concepts

How Verklet runs Node.js-style workloads in a browser tab — workers, OPFS, service workers, WASM.

Verklet is built from four browser primitives, each doing one job. None of them is new; the work is in stitching them into something that feels like a real Node host.

Web Workers — process isolation

Every "process" in Verklet is a Web Worker. The main thread doesn't execute user code. It owns the runtime container and the UI; user processes run in workers that get their own message channel, their own stdio streams, and their own crash boundary.

This matters because:

You don't manage workers directly. runtime.spawn() allocates them; process exit reclaims them.

OPFS — persistent storage

The virtual filesystem lives in memory while a session is open. When you pass persistenceKey to Runtime.boot(), Verklet writes a content-addressed snapshot to the Origin Private File System — a per-origin sandbox that survives reloads but is invisible to other sites.

What that gets you:

OPFS support varies. Chromium and Firefox are solid; WebKit is partial. Verklet detects this at boot via capabilities.opfs and degrades to in-memory if necessary — your code runs either way.

Service Workers — preview routing

When a process inside the runtime opens a port, that port doesn't actually exist at the network level. The browser has no concept of "an HTTP server in a worker." So Verklet registers a service worker at your origin that intercepts requests to a preview path (/__runtime by default) and routes them into the runtime as in-process function calls.

The upshot:

The service worker is registered automatically on Runtime.boot(). If you've disabled service workers in your hosting setup, pass serviceWorker: false and use runtime.fetchPreview() directly.

WebAssembly — the hot paths

Anything that needs to be fast or POSIX-shaped is WASM. The synchronous virtual filesystem (so fs.readFileSync works without yielding to the event loop), the package archive parser, the path-traversal validator, and a handful of binary codecs all live in Rust-built WASM modules.

JavaScript handles policy and orchestration. WASM handles the bytes. This split is why a Node process inside Verklet can call fs and Buffer APIs without the runtime stalling on every read.

Putting it together

A typical boot looks like this:

From the user's perspective they opened a tab and typed code. From the host's perspective, four pieces clicked together and a Node-shaped sandbox came up. See the compatibility matrix for what behaviour is wired up today.