node:worker_threads for offloading work to separate JavaScript
contexts. The API is the standard Node one — Worker, parentPort, workerData,
postMessage, terminate, MessageChannel/MessagePort, receiveMessageOnPort
— so existing worker code and tools like jest-worker, Vite/Rollup worker pools,
and miniflare’s synchronous-fetch handshake run unmodified.
Workers are a
node-compat feature: node:worker_threads is
part of the Node surface and is withdrawn in strict-web.The thread-per-worker model
Eachnew Worker(...) gets its own OS thread, its own V8 isolate, and its own
single-threaded async runtime. Workers share nothing but the message channel
(and any SharedArrayBuffer you explicitly pass).
This is a deliberate, correctness-driven choice. A V8 isolate is entered when it’s
constructed and only exited when it’s dropped, in strict LIFO order per OS thread —
so two long-lived isolates simply cannot be interleaved on one thread. A thread
apiece is the only sound model (and it’s what Node and Deno do). meow makes it
cheap: each worker reuses the project’s immutable resolution graph and
content-addressed cache by reference (no re-resolution, no lockfile re-parse) and
boots from the same V8 startup snapshot as the main isolate, so only the
structured-cloned message payloads ever cross the boundary.
Each worker is its own OS thread with its own V8 isolate and event loop; they communicate only through serialized messages (and SharedArrayBuffer for shared memory).
Example
What’s supported
The combination of transferable
MessagePort, SharedArrayBuffer + Atomics, and
receiveMessageOnPort is exactly what a synchronous fetch over an async
boundary needs — the pattern SvelteKit’s Cloudflare adapter uses when its
prerender worker drives miniflare. Nested workers let that prerender worker spin up
miniflare’s fetcher on its own thread.
Next: environment variables
Every MEOW_* variable and how process.env behaves per mode.