> ## 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.

# Runtime modes

> strict-web vs node-compat — what each exposes, how determinism differs, and which to choose.

Every meow project runs in one of two modes. The mode decides **which global
surface your code sees** and **whether the run is deterministic by default**. You
set it once in `meow.config.json`:

```json meow.config.json theme={null}
{ "mode": "strict-web" }
```

## The two modes at a glance

<Columns cols={2}>
  <Card title="strict-web" icon="globe" color="#7CC7FF">
    A portable, web-standard sandbox. Only WinterTC-style web globals are present;
    Node host APIs are withdrawn. **Deterministic by default.** Great for libraries,
    edge/serverless functions, and anything you want reproducible.
  </Card>

  <Card title="node-compat" icon="node-js" color="#98FF98">
    The full Node.js surface: `node:*` built-ins, CommonJS, `process`, `fs`,
    `child_process`, N-API. **Full host access by default.** Use it for Node apps and
    frameworks like Next.js, Vite, Astro.
  </Card>
</Columns>

<Note>
  **Two different defaults.**

  * `meow init` writes `{ "mode": "strict-web" }`. A freshly scaffolded project is deterministic.
  * A project with **no `meow.config.json` at all** falls back to **`node-compat`**, so dropping meow into an existing Node repo behaves like Node from the first run.
</Note>

## What each mode exposes

| Capability                                               | `strict-web`  | `node-compat` |
| -------------------------------------------------------- | ------------- | ------------- |
| `fetch`, `Request`, `Response`, `Headers`, `FormData`    | ✅             | ✅             |
| `URL`, `URLPattern`, `URLSearchParams`                   | ✅             | ✅             |
| `crypto.subtle`, `TextEncoder`/`TextDecoder`, `Blob`     | ✅             | ✅             |
| `AbortController`/`AbortSignal`, `setTimeout`, `console` | ✅             | ✅             |
| `meow:http`, `meow:ui` built-in modules                  | ✅             | ✅             |
| `node:*` built-ins (`fs`, `path`, `crypto`, `os`, …)     | ❌ withdrawn   | ✅             |
| `process` global, `process.env`, `process.argv`          | ❌ removed     | ✅             |
| CommonJS `require()`                                     | ❌             | ✅             |
| npm packages that need Node built-ins                    | ❌             | ✅             |
| N-API native addons, `child_process`                     | ❌             | ✅             |
| Clock / randomness / env                                 | deterministic | real host     |

In `strict-web`, touching a withdrawn Node API is a clear, fix-pointing error
rather than a silent `undefined`:

```typescript theme={null}
import fs from "node:fs";       // import resolves...
fs.readFileSync("x");           // ...but throws ERR_STRICT_WEB_WITHDRAWN at use
```

<Note>
  Both modes share the same web layer — `fetch` and friends are always present.
  The mode only changes the **Node host surface** and the **determinism defaults**.
  The full strict-web global list is on the [Web APIs](/runtime/web-apis) page.
</Note>

## Determinism differs by mode

This is the part that surprises people, so it's worth stating directly.

<Tabs>
  <Tab title="strict-web (deterministic)">
    By default the run is hermetic:

    * `Date.now()` / `new Date()` return a **fixed virtual epoch**, advancing only as timers fire.
    * `Math.random()` and `crypto.getRandomValues()` draw from a **seeded ChaCha20 stream**.
    * The timezone is pinned to **UTC** and the locale fixed, so `Date`/`Intl` render identically everywhere.
    * Environment variables are **invisible** (`process.env` is empty; there is no `process` global at all).

    Two machines run the same code and get the same bytes. Opt back into the real
    host per-capability with `--allow-clock`, `--allow-random`, `--allow-env`, or
    `--trust`. See [Determinism](/concepts/determinism) and [Permissions](/concepts/permissions).
  </Tab>

  <Tab title="node-compat (real host)">
    By default the run behaves like Node:

    * Real wall-clock and monotonic time.
    * OS entropy for randomness.
    * Full environment variables.

    This is what frameworks expect. If you want a node-compat run to be reproducible
    for a specific command, you can still scope it down — but the *default* is the
    live host.
  </Tab>
</Tabs>

<Warning>
  `meow test` always runs in a **deterministic strict-web isolate**, regardless of
  your project mode. Tests are reproducible by construction. If a test needs the
  real clock or host env, that's a deliberate exception you grant — not the default.
</Warning>

## Choosing a mode

<AccordionGroup>
  <Accordion title="Pick strict-web when…" icon="globe">
    * You're writing a library, an edge/serverless handler, or a Cloudflare-Workers-style function.
    * You want reproducible builds and tests with no hidden host dependencies.
    * Your code targets web standards (`fetch`, `Request`/`Response`, `crypto.subtle`) and doesn't need `node:fs` or `process`.
  </Accordion>

  <Accordion title="Pick node-compat when…" icon="node-js">
    * You're running Next.js, Vite, Astro, Playwright, Puppeteer, or any Node framework.
    * Your dependencies reach for `node:fs`, `child_process`, `process.env`, or native addons.
    * You're migrating an existing Node app and want it to behave like Node from day one.
  </Accordion>
</AccordionGroup>

```bash theme={null}
meow init                      # strict-web (default)
meow init --mode node-compat   # full Node surface
```

You can change the mode at any time by editing `meow.config.json` and re-running
`meow sync`.

<Card title="Next: how determinism actually works" icon="lock" href="/concepts/determinism">
  The clock, RNG, and env seam that powers strict-web.
</Card>
