Performance & Zero-JS
Performance you start with, not bolt on
Section titled “Performance you start with, not bolt on”Most frameworks make you claw performance back: you build the app, it’s slow, and you optimize. Astro inverts that — you start at a fast baseline (static HTML, zero JavaScript) and your job is to not lose it. Every kilobyte of client JavaScript is one you added deliberately, so the question is always “does this really need to ship?”
Choose the cheapest client directive
Section titled “Choose the cheapest client directive”The islands lesson covered what the client directives do; here’s the performance framing. The directive you pick decides how much JavaScript runs, and when:
| Directive | Ships & runs JS | Use when |
|---|---|---|
client:load | Immediately on page load | Critical, above-the-fold interactivity (rare) |
client:idle | When the browser goes idle | Interactive, but not needed instantly |
client:visible | When it scrolls into view | Below-the-fold islands (the best default) |
client:media | Only at a breakpoint | A mobile-only or desktop-only widget |
The rule of thumb: reach for client:visible (or client:idle) before client:load. A carousel three screens down doesn’t need its JavaScript during initial load; hydrating it with client:visible keeps that cost off the critical path. Overusing client:load quietly rebuilds the “everything hydrates upfront” cost Astro exists to avoid.
flowchart LR load["client:load"] --> upfront["JS on the critical path (heaviest)"] idle["client:idle"] --> later["JS after first paint"] visible["client:visible"] --> onscroll["JS only when scrolled into view (lightest)"]
Prefetch for instant navigation
Section titled “Prefetch for instant navigation”Fast first load is half the story; fast navigation is the other half. Astro can prefetch a page’s HTML before the user clicks, so the next page is essentially instant. Enable it in config, then it prefetches links on hover/viewport by default, or opt a link in explicitly:
<a href="/pricing" data-astro-prefetch>Pricing</a>Paired with <ClientRouter />, prefetch makes multi-page navigation feel like a SPA — the HTML is already in the browser cache when the click happens — without a client-side data layer.
Measure what you actually shipped
Section titled “Measure what you actually shipped”Don’t optimize by vibes. Two things to look at:
- The islands you shipped. Build the site and check which components actually became islands (and with which directive). A component you thought was static but is hydrating is wasted JavaScript; a
client:loadthat could beclient:visibleis misplaced cost. - Lighthouse / Core Web Vitals. Run Lighthouse (in Chrome DevTools) against the built site. Watch Largest Contentful Paint (usually your hero image — see the assets lesson), Cumulative Layout Shift (reserve image/font space), and Total Blocking Time (your island JavaScript).
The Astro baseline usually scores near-perfect out of the box. When a score drops, it’s almost always one of: an unoptimized image, a font causing shift, or an island hydrating more eagerly than it needs to.