node-compat mode, meow layers the full Node.js surface on
top of its web baseline. The Node built-ins, CommonJS, and N-API support are
provided by Deno’s battle-tested Node-compatibility crates, so real packages and
frameworks run unmodified.
meow.config.json
What’s available
node: built-ins
node:fs, node:path, node:os, node:crypto, node:process,
node:child_process, node:worker_threads, node:http, and the rest of the
standard library.CommonJS & ESM
require() and import interop, with correct CJS/ESM classification and the
Node resolution algorithm.The process global
process.argv, process.env, process.cwd(), process.exit(),
process.platform/arch, process.pid/ppid, and IPC via process.send.Native addons
N-API native modules load through the same package graph.
Frameworks run out of the box
meow boots real frameworks on its tuned V8 build — no toy examples:Next.js
Vite
Astro
Playwright
Puppeteer
Jest workers
The node shim
This is what makes framework tooling “just work.” When meow runs your code, it writes shim executables into~/.meow/bin and puts that directory first on
PATH:
- Runtime shims —
node,npm,pnpm,yarn,bun— proxy straight back into meow. - Ephemeral shims —
npx,pnpx,bunx— proxy intomeow x.
node ./worker.js, the call
transparently re-enters meow with the same project context. You don’t reconfigure
how tools invoke each other.
The shims are created during meow run and meow install (not by meow add
alone). meow also sets NODE and npm_node_execpath to the shimmed node so
tools that spawn “the current Node” find their way back.
Child processes & IPC
child_process.fork IPC works, including the binary-safe message channel that
jest-worker and Turbopack workers rely on. meow honors the standard
NODE_CHANNEL_FD / NODE_CHANNEL_SERIALIZATION_MODE protocol, so process.send()
and 'message' events behave as Node programs expect.
For in-process parallelism, see Workers, which run as
cooperative V8 isolates on meow’s event loop.
Module resolution
meow’s single resolver handles bothimport and require(). It applies a fixed,
deterministic condition priority rather than Node’s author-insertion order:
| Context | Conditions tried, in order |
|---|---|
import (ESM) | meow → import → node → default |
require() (CJS) | meow → require → node → default |
For a package whose
exports lists both node and import, meow deterministically
prefers import regardless of the order the author wrote the keys — a deliberate
divergence from Node’s insertion-order selection that keeps resolution reproducible.
In practice it matches what virtually all packages intend.require() treats it as CommonJS
(the Node-correct default), with a fallback to the ESM translator on a genuine ESM
syntax error — so mixed-module dependencies resolve correctly.
Lockfile compatibility
Some framework detectors look for apackage-lock.json. meow can write a tiny
compatibility marker without giving up its own lockfile:
package-lock.json flagged meowCompatibilityLockfile.
Your meow.lock.jsonl remains the authoritative resolution.
Next: workers
Cooperative V8 isolates for parallelism.