Skip to content

Performance foundations

MetricGoodNeeds workPoor
LCP2.5 s or less2.5-4.0 sOver 4.0 s
INP200 ms or less200-500 msOver 500 ms
CLS0.1 or less0.1-0.25Over 0.25

Measure at the 75th percentile on mobile. A fast desktop score does not prove a fast experience for most visitors.

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-revalidate

Never cache HTML with the same immutable policy as hashed assets. A stale shell can pin users to an old deployment.

  • 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 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.

{
"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.