Performance foundations
Core Web Vitals targets
Section titled “Core Web Vitals targets”| Metric | Good | Needs work | Poor |
|---|---|---|---|
| LCP | 2.5 s or less | 2.5-4.0 s | Over 4.0 s |
| INP | 200 ms or less | 200-500 ms | Over 500 ms |
| CLS | 0.1 or less | 0.1-0.25 | Over 0.25 |
Measure at the 75th percentile on mobile. A fast desktop score does not prove a fast experience for most visitors.
Asset and cache strategy
Section titled “Asset and cache strategy”Vite fingerprints imported assets, so they can be cached forever while HTML stays short-lived:
# public/_headers (Cloudflare Pages)/_astro/* Cache-Control: public, max-age=31536000, immutable
/* Cache-Control: public, max-age=0, must-revalidateNever cache HTML with the same immutable policy as hashed assets. A stale shell can pin users to an old deployment.
JavaScript discipline
Section titled “JavaScript discipline”- Keep public pages static and hydrate only interactive islands.
- Load analytics and other third-party scripts away from the main thread where possible.
- Split application routes so the first load does not include every feature.
- Audit the bundle after each release, not only at launch.
- Prefer CSS and native browser behaviour over JavaScript for menus, disclosures and simple animation.
Images and fonts
Section titled “Images and fonts”Images usually dominate LCP. Serve responsive widths, modern formats and an explicit sizes value. Prioritise the hero image and lazy-load everything below the fold.
---import { Image } from 'astro:assets';import hero from '@assets/images/modern-web-apps-hero.png';---<Image src={hero} alt="Engineering team reviewing a deployment dashboard" widths={[640, 960, 1280]} sizes="(min-width: 1024px) 50vw, 100vw" loading="eager" fetchpriority="high"/>For the full image pipeline, see Sharp images. For third-party scripts, see Partytown analytics.
Fonts should be self-hosted or preconnected, subset where possible, and loaded with font-display: swap. Avoid layout shift by matching fallback metrics or reserving space.
Measurement
Section titled “Measurement”{ "ci": { "collect": { "url": ["https://preview.example.com/", "https://preview.example.com/docs/"], "numberOfRuns": 3 }, "assert": { "assertions": { "categories:performance": ["error", { "minScore": 0.9 }], "largest-contentful-paint": ["error", { "maxNumericValue": 2500 }], "cumulative-layout-shift": ["error", { "maxNumericValue": 0.1 }] } } }}Run Lighthouse CI against the preview artifact, then promote the same artifact to production. Testing a different build defeats the purpose.
