# Determinism and Runtime Rules

> The runtime rules that let the same component tree render identically on the server and in the browser.

Source: [https://askrjs.com/docs/core-concepts/determinism](https://askrjs.com/docs/core-concepts/determinism)

Status: stable. Packages: @askrjs/askr.

**Published packages are authoritative.** Examples may lag behind a published contract. When guidance differs, verify the exports and TypeScript declarations in your installed package, then file an issue.

## Example

Put reactive state inside the component that owns the interaction and derive display values from it during render.

```tsx
import { derive, state } from '@askrjs/askr';

export function Quantity() {
  const [count, setCount] = state(1);
  const label = derive(() => 'Quantity: ' + count());

  return <button onClick={() => setCount((value) => value + 1)}>{label()}</button>;
}
```

## Render purity

A component function must return the same output for the same props and state on every call — the runtime depends on this to decide what changed and patch only that part of the DOM. Fetching data, subscribing to external events, or mutating shared objects directly inside a component body breaks that guarantee; those belong behind `resource`, `on`, or `task` instead, which run outside the render pass and hand results back through reactive values. Two rules follow directly from re-running the whole function on every update, and the runtime enforces both at runtime, not just by convention: `state()`, `derive()`, lifecycle calls, and `<For>` must run in the same order on every render of a given component — wrapping one of them in a plain `if` (instead of `<Show>`/`<Case>`) throws once the sequence changes — and calling a state setter during render itself (rather than from an event handler or effect) throws `[Askr] state.set() cannot be called during component render.` because it would recurse into another render of the same component.

## Stable initial state

`state()` initializers run once, on first render, and are expected to be pure — if the seed value depends on something nondeterministic (like `Math.random()` or `Date.now()`), server-rendered markup and the client's first hydration pass will disagree. Deriving that value from a stable input (a route param, a server-supplied seed) instead keeps the first render identical on both sides.

## Browser-only work

Code that touches `window`, `document`, or other browser globals can't run during server rendering, since none of those exist in a Node process. Gate that work behind lifecycle helpers like `task` or `resource`, which only execute after mount on the client, rather than reading browser globals directly in the component body where SSR would throw.

## Hydration diagnostics

Server-side rendering shares a `DocumentRenderContext` — including a `seed` value — with the client so both passes render the same output from the same inputs; when they disagree, the runtime surfaces a hydration mismatch. The check itself is a whole-document string comparison (server-rendered markup against a fresh server-side re-render, both normalized), so the diagnostic is a single generic message — `[Askr] Hydration mismatch detected. Server HTML does not match expected server-render output.` — rather than a pointer at which specific subtree diverged. `devWarningsEmitted` on the component instance is a separate mechanism entirely, used for unused-state-variable and slow-render warnings, not hydration.

## Documentation navigation

[Previous](https://askrjs.com/docs/core-concepts/error-boundaries/index.md) | [Next](https://askrjs.com/docs/routing/index.md)
