#Zero-JS by Default
Components without "use client" generate no client JavaScript:
// Server-only — 0 bytes of client JS
export function Header() {
return (
<header>
<h1>My App</h1>
<nav>...</nav>
</header>
)
}#Minimal Hydration
Only signals, event handlers, and effects are sent to the client. The HTML structure is never re-created — the server already rendered it.
#Reducing Client JS Size
#Use Memos for Derived Values
// ❌ Redundant signal
const [count, setCount] = createSignal(0)
const [doubled, setDoubled] = createSignal(0)
createEffect(() => setDoubled(count() * 2)) // Extra signal + effect
// ✅ Use memo instead
const [count, setCount] = createSignal(0)
const doubled = createMemo(() => count() * 2) // Computed, no extra signal#Prefer Static Arrays
The compiler detects static arrays and skips reconciliation:
// Static — no reconciliation generated
const tabs = ['Home', 'About', 'Contact']
{tabs.map(tab => <Tab label={tab} />)}
// Dynamic — reconcileElements needed
const [items, setItems] = createSignal([...])
{items().map(item => <Item key={item.id} data={item} />)}#Optimizing Hydration
#Stable Keys for Lists
// ✅ Stable key — DOM nodes reused when list changes
{items().map(item => <li key={item.id}>{item.name}</li>)}
// ❌ Index key — DOM nodes recreated on reorder
{items().map((item, i) => <li key={i}>{item.name}</li>)}#Focus Preservation
The reconciler preserves focused elements during list updates automatically.
#Optimizing Reactivity
#`untrack` for One-Time Reads
createEffect(() => {
// Only re-runs when items() changes, not when count() changes
const currentCount = untrack(() => count())
console.log(`${items().length} items, count was ${currentCount}`)
})#Memo Over Effect + Signal
// ❌ Effect → Signal chain (two subscriptions)
const [total, setTotal] = createSignal(0)
createEffect(() => setTotal(price() * quantity()))
// ✅ Single memo (one subscription)
const total = createMemo(() => price() * quantity())#Guard DOM Updates
createEffect(() => {
const cls = isActive() ? 'active' : 'inactive'
if (element.className !== cls) {
element.className = cls // Only touches DOM when value changes
}
})The compiler already generates guarded updates for text content and common attributes. This applies to custom effects only.