Location transparency
The same pure-computation call produces the same result regardless of which host runs it. clamp(x, 0, 10), json.stringify(items), and date.format(t, layout) mean the same thing in a > server handler, a server-side render, a reactive patching the DOM, or a button's on_click[...] attribute. The substrate routes the call to whichever host is fastest for the site — but the result of computing it never changes.
Same call, three compile paths
clamp in server render and a handler
The interpolated 3 below evaluates server-side on first paint, then re-evaluates in the browser whenever p_count changes. The same clamp(...) call in the on_click handler runs entirely in the browser — no server round-trip — and logs the same value to the console.
> page
p_count: 3
<p> [clamp(p_count, 0, 5)]
<button on_click[p_count++]> +1
<button on_click[log[clamp(p_count, 0, 5)]]> log clamp clamp(p_count, 0, 5) = 3
Namespaces transfer too
json.stringify works identically server and client
Namespace members follow the same rule. The interpolation renders the stringified person on first paint; the handler stringifies the live person object at click time and logs it. Same call, two execution sites, one semantic.
> page
person: {first: 'Grace', last: 'Hopper'}
<p> [json.stringify(person)]
<button on_click[log[json.stringify(person)]]> log JSON {"first":"Grace","last":"Hopper"}
What qualifies as pure
Value-in, value-out — no I/O, no provider commitment
The line is sharp on purpose. Pure computation gets a JS twin and runs wherever the call sits: strings, math, collections, regex, date, json, encoding, plus log / debug / error. Effects (databases, services, Tail, HTTP, the filesystem) commit to a host because that's where the I/O lives — calling them from the wrong tier round-trips through dispatch instead of running locally.
# Pure — runs in place wherever you write it:
<p> [round(p_count * 1.5)]
<button on_click[log[round(p_count * 1.5)]]> log
# Effectful — round-trips to where the host lives:
<button on_click[main_db.users.add({name: 'Ada'})]> add user
<button on_click[auth.login(name, pw)]> login User-defined functions still round-trip
Not a leak — it is the correct routing
Your own > name declarations live on the server and need access to server state, so calling them from a handler issues an RPC. That's not a violation of the rule — they're not pure-computation primitives, they're application logic with a deployment target. The rule only commits the substrate's own builtins to dual-tier execution.
> add[a, b] >> a + b # user-defined → round-trips
> clamp_to_5[x] >> clamp(x, 0, 5) # also round-trips
<button on_click[log[add(1, 2)]]> # one RPC per click
<button on_click[log[clamp(1 + 2, 0, 5)]]> # zero RPCs Why this matters for authoring
Build the mental model once, write the call where it reads best
Location transparency lets you write a function by what it does, not by where it'll run. Moving a piece of logic from a reactive client-side path to a server-tier handler — or back — is a performance decision, not a semantic one. The author's mental model stays: "this transforms input to output; tier is a deployment knob."
That closes the advanced section. Head back to the docs index for the rest of the library.