Mental Model
Vango is a server-driven UI framework with a strict ownership model. Most mistakes in Vango come from importing habits from client-heavy web frameworks.
Server-driven UI
In Vango:
the server owns state
the server renders UI
the browser sends events
the browser applies patches
The browser is not the source of truth.
That means UI is a projection of server state, event handlers mutate server state, and rerendering happens on the server.
The session loop is the single writer
Each connected browser tab has a session. Each session has a single-writer event loop.
That gives you:
serialized signal writes
deterministic rerenders
fewer accidental write races
The most important rule in Vango is simple: all reactive writes must happen on the session loop.
If code runs off-loop, bring it back through a framework boundary such as setup.Resource, setup.Action, a page Action, or ctx.Dispatch(...) for external integrations.
Where code runs
| Setup | No | Yes | No |
|---|---|---|---|
| render | No | No | No |
| event handler | No | No | Yes |
| Resource loader | Yes | No | No |
setup.Action work / page Action | Yes | No | No |
| hook / island / WASM code | browser-local only | browser-local only | browser-local only |
Use that table literally.
Initial load and reconnect
Typical flow:
browser requests a page
server matches the route and renders HTML
browser shows content
runtime script connects to the live endpoint
browser events go over the live transport
server rerenders and sends patches
Reconnect behavior is explicit. Successful resume may use a full resync to realign browser DOM with the rebuilt server tree. If SSR and WebSocket route agreement drift apart, you can get patch mismatches, reconnect loops, or state that seems attached to the wrong page.
Purity rules
Setup:
allocates state
registers lifecycle
stays non-blocking
Render:
computes UI from current state
stays deterministic
does not allocate
does not write state
Resources and Actions:
own blocking work
run off-loop
return results through the framework
Effects:
run after commit
react to dependency changes
stay bounded and non-blocking
Performance model
The expensive place is the session loop. Keep render closures, event handlers, and synchronous effect bodies cheap.
Move expensive work to:
Resource loaders
setup.Action work functions
page Action handlers
Also remember:
unstable list keys create large patches
uncontrolled client DOM mutation creates patch mismatches
too much persisted state hurts resume time
Stop signs
If you hit any of these, stop and fix the contract violation instead of papering it over:
repeated self-heal reloads
navigation that only works after refresh
list bugs after reorder or filtering
pressure to mutate server-owned DOM from the client
desire to jump to low-level packages because the first implementation is fighting the framework
Forbidden fixes
Do not:
add location.reload to mask patch mismatches
call ctx.Navigate(...) in a page handler or render closure
use unstable list keys
repair server-owned DOM with inline scripts after boot
write signals from Resource loaders or Action workers
reach for low-level pkg/* packages for ordinary app code
What to read next
Components and Setup for stateful component structure
State and Async Work for signals, resources, and actions
Client Boundaries for hooks, islands, and WASM