> ## Documentation Index
> Fetch the complete documentation index at: https://docs.meow.style/llms.txt
> Use this file to discover all available pages before exploring further.

# Coming from Node.js

> Map your npm, node, npx, and pnpm muscle memory onto meow — and learn what's genuinely different.

meow is designed to be a **drop-in** for most Node.js projects. It reads your
existing `package.json`, resolves the same npm packages, and runs the same
frameworks. This page maps what you already type onto meow, then calls out the few
things that are deliberately different.

## Command cheat sheet

<CodeGroup>
  ```bash Running code theme={null}
  node script.js          →  meow run script.js   (or: meow script.js)
  node --eval "..."       →  meow -e "..."
  npm run dev             →  meow dev              (or: meow run dev)
  npm run build           →  meow build            (omni-router → meow run build)
  npm start               →  meow start
  ```

  ```bash Packages theme={null}
  npm install             →  meow install          (or: meow i)
  npm install zod         →  meow add zod
  npm install -D vitest   →  meow add -D vitest
  npm uninstall zod       →  meow remove zod
  npm install -g <tool>   →  meow add -g <tool>
  npm search <q>          →  meow search <q>
  ```

  ```bash Ephemeral / npx theme={null}
  npx create-vite app     →  meow x create-vite app   (or: meow create-vite app)
  npx prettier .          →  meow x prettier .
  ```
</CodeGroup>

### The omni-router

meow infers intent from bare invocations, so most habits keep working without the
`run` verb. When the first argument isn't a known command, meow routes it:

| You type               | meow runs                | Because                           |
| ---------------------- | ------------------------ | --------------------------------- |
| `meow build`           | `meow run build`         | `build` is a standard script name |
| `meow ./app.ts`        | `meow run ./app.ts`      | it's a file path                  |
| `meow dev`             | `meow run dev`           | `dev` is a script                 |
| `meow create-next-app` | `meow x create-next-app` | unknown → ephemeral package       |

It also strips competitor-specific flags (`--shell`, `--silent`, `--no-warnings`)
and Deno-style run flags (`-A`, `--allow-all`, `--unstable-*`) so scripts copied
from other ecosystems don't crash the parser. Full details in
[Running code](/runtime/running-code#the-omni-router).

### The `node` shim

When meow runs your scripts, it puts shims for `node`, `npm`, `pnpm`, `yarn`,
`bun`, `npx`, `pnpx`, and `bunx` first on `PATH`. So when a framework (Next.js,
Vite, Jest workers) shells out to `node`, it transparently re-enters meow. You
don't have to change how tools invoke each other.

<Tip>
  Need a real `node` for one command? Set `MEOW_NO_SHIM=1` and the shim execs the
  system binary instead.
</Tip>

## File-for-file

| Node ecosystem                                           | meow                                   | Notes                                                                                                                                                   |
| -------------------------------------------------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `package.json`                                           | `package.json`                         | **Same file.** meow reads `dependencies`, `devDependencies`, `scripts`, `overrides`, `workspaces`. It only edits dependency sections on `add`/`remove`. |
| `package-lock.json` / `pnpm-lock.yaml`                   | `meow.lock.jsonl`                      | A strict, sorted, merge-resistant JSON-Lines lockfile. See [the lockfile](/package-manager/lockfile).                                                   |
| `node_modules/`                                          | `node_modules/`                        | Still real directories (no symlinked package contents), materialized via copy-on-write/hardlinks.                                                       |
| `.eslintrc`, `.prettierrc`, `tsconfig.json`, test config | `meow.config.json`                     | One config. meow generates the `tsconfig.json` editors expect. See [configuration](/configuration/meow-config).                                         |
| `tsc`, `eslint`, `prettier`, `jest`/`vitest`             | `meow check` / `lint` / `fmt` / `test` | Built in. No separate installs.                                                                                                                         |
| `webpack`/`esbuild`/`rollup`                             | `meow bundle`                          | Powered by Rolldown over meow's resolver.                                                                                                               |

<Note>
  meow can also write a tiny `package-lock.json` **compatibility marker** so
  framework detectors that look for it still light up — `meow install --compat-lockfile`.
  Your `meow.lock.jsonl` stays the source of truth.
</Note>

## What's genuinely different

These are intentional. Knowing them up front saves surprises.

<AccordionGroup>
  <Accordion title="Runs are deterministic by default (in strict-web mode)" icon="lock">
    A fresh `meow init` project runs in **`strict-web`** mode: the clock is frozen,
    `Math.random`/`crypto.getRandomValues` are seeded, and the timezone is pinned to
    UTC. Code that reads `Date.now()` expecting real wall-clock time will see a fixed
    value until you grant the real clock with `--allow-clock` (or switch to
    `node-compat`). This is what makes tests and CI reproducible. See
    [Determinism](/concepts/determinism).
  </Accordion>

  <Accordion title="Host access is a grant, not a given (in strict-web mode)" icon="shield-halved">
    In `strict-web`, environment variables are invisible and `node:fs`/`node:process`
    throw `ERR_STRICT_WEB_WITHDRAWN`. You opt back in with `--allow-env`, `--allow-clock`,
    `--allow-random`, or `--trust`. In **`node-compat`** mode (use it for Node apps and
    frameworks) the full host surface is available like Node. See [Permissions](/concepts/permissions).
  </Accordion>

  <Accordion title="Bare versions are exact, like npm — not caret, like Cargo" icon="code-branch">
    `"zod": "3.23.8"` means **exactly** `3.23.8`. `"3.23"` means `>=3.23.0 <3.24.0`,
    `"3"` means `>=3.0.0 <4.0.0`. `^`, `~`, `||`, and hyphen ranges all behave the
    npm way. npm aliases (`npm:pkg@range`) and dist-tags (`latest`) are supported.
  </Accordion>

  <Accordion title="No global mutable state between tools" icon="layer-group">
    There is no `.eslintcache`, no per-tool daemon, no separate `tsc --watch` server.
    meow holds one syntax graph in memory for the lifetime of a command and feeds every
    tool from it.
  </Accordion>
</AccordionGroup>

## A typical migration

<Steps>
  <Step title="Drop meow into the repo">
    Keep your `package.json`. Add a `meow.config.json`:

    ```json meow.config.json theme={null}
    { "mode": "node-compat" }
    ```

    `node-compat` is the safe starting point for an existing Node app — full Node
    surface, host access, real clock.
  </Step>

  <Step title="Install">
    ```bash theme={null}
    meow install
    ```

    This resolves your existing dependencies, writes `meow.lock.jsonl`, and
    materializes `node_modules`.
  </Step>

  <Step title="Generate editor shims">
    ```bash theme={null}
    meow sync
    ```

    Writes `.meow/tsconfig.json` and a root `tsconfig.json` shim so your editor and
    `meow check` agree on the type surface.
  </Step>

  <Step title="Run your scripts">
    ```bash theme={null}
    meow dev
    meow run build
    meow test
    ```
  </Step>
</Steps>

<Card title="Next: the two runtime modes" icon="toggle-on" href="/concepts/modes">
  The single most important concept when moving a project to meow.
</Card>
