Overview

Core Web Vitals cover three metrics; page speed has at least six worth tracking. TTFB, FCP, image weight, font loading, and JS payload all decide whether a page hits its LCP and INP targets. The fixes are cheap on a new build and expensive on a legacy one; ship them at architecture time, not after a Lighthouse audit. For the end-to-end CWV optimization walkthrough, see optimize-core-web-vitals.

Cut TTFB to under 800 milliseconds

Time to First Byte is server response time plus network latency. web.dev treats 0.8 seconds at p75 as a rough “good” guide; TTFB is not a Core Web Vital. It is the floor under every other metric: with a 1.5-second TTFB, the page has only one second left for everything else before LCP misses 2.5 seconds.

  • Static-host whenever possible. GitHub Pages, Vercel, Netlify, and Cloudflare Pages serve from a CDN edge by default.
  • For dynamic responses, cache HTML at the edge with s-maxage and stale-while-revalidate. A 60-second SWR window absorbs traffic spikes. See cloudflare-cache-rules for the rule syntax.
  • Use a CDN with broad edge coverage, such as cloudflare, so cached HTML is served near the user.
  • Database round-trips inside the request handler are the most common TTFB killer. Cache reads, batch queries, or move the page to static.

Hit First Contentful Paint under 1.8 seconds

FCP is the first pixel of content rendered. It is a proxy for “is anything happening?” and decides whether users abandon the page.

  • Inline critical CSS and defer the rest; see render-blocking-resources.
  • Render the first paint server-side. A blank <div id="root"> waiting for client React makes FCP equal to JS parse time.
  • Preconnect to the CDN and font origin: <link rel="preconnect" href="https://fonts.example.com" crossorigin>.

Serve images in modern formats with lazy loading

Images are often the largest share of page weight. AVIF and WebP usually produce much smaller files than JPEG or PNG at similar visual quality; measure the savings on your own images.

  • AVIF first, WebP second, JPEG as fallback. Use <picture> with <source type="image/avif"> and <source type="image/webp">.
  • Lazy-load every image below the fold with loading="lazy". Native browser support is universal as of 2023.
  • Eager-load the LCP image with fetchpriority="high" and a <link rel="preload"> in <head>.
  • Specify width and height on every <img> to reserve layout space; CLS depends on it. See image-seo for the full image SEO checklist.

Remove render-blocking CSS, fonts, and scripts

Stylesheets, web fonts, and synchronous scripts all hold back the first paint. Inline critical CSS, load fonts with font-display: swap, and defer non-essential JavaScript. See render-blocking-resources for the patterns and code.

Measure both field data and synthetic budgets

Synthetic tools find regressions before they ship; field data confirms real-world impact.

  • Lighthouse CI in the build pipeline, failing the build when a metric crosses the budget you set.
  • WebPageTest with throttled 4G and a mid-tier phone profile. Lab runs on a Mac M-series do not reflect users.
  • Field data through the web-vitals library and CrUX. See core-web-vitals for the field-data setup.
  • Set per-page budgets in lighthouserc.json. Start from the current measured weight and tighten; the numbers are a team choice, not a Google threshold.