Skip to content

Appendix D — Glossary & tooling reference


Glossary

Metrics

Term Definition
LCP Largest Contentful Paint — when the largest image or text block in the viewport rendered. Good ≤ 2.5 s at p75.
INP Interaction to Next Paint — approximately the worst interaction latency across the page's life, measured to the next painted frame. Good ≤ 200 ms. Replaced FID in March 2024.
CLS Cumulative Layout Shift — the largest burst (session window) of unexpected layout movement. Good ≤ 0.1.
TTFB Time to First Byte — network latency plus server processing.
FCP First Contentful Paint — when any content first painted. Can be a skeleton.
TBT Total Blocking Time — sum of main‑thread blocking beyond 50 ms per task, between FCP and TTI. A lab proxy for INP.
TTI Time to Interactive — largely superseded by INP and TBT.
p75 75th percentile. Three of four page views were at least this good. The threshold CWV uses.
Long task A main‑thread task ≥ 50 ms. Anything longer makes input feel laggy.
LoAF Long Animation Frame — an API attributing slow frames to specific scripts. The best INP diagnostic.

Rendering

Term Definition
SSG Static Site Generation — HTML built at build time.
ISR Incremental Static Regeneration — static HTML regenerated on a timer or on demand.
SSR Server‑Side Rendering — HTML generated per request.
CSR Client‑Side Rendering — HTML generated in the browser after JS loads.
PPR Partial Prerendering — a static shell served instantly with dynamic holes streamed into the same response.
RSC React Server Components — components that render on the server and ship zero JavaScript.
RSC payload The serialized component tree sent alongside HTML, inlined as self.__next_f.push(...).
Hydration React attaching event handlers and state to server‑rendered HTML, making it interactive.
Streaming SSR Sending HTML in chunks as it's rendered, so the browser starts work before the server finishes.
Islands Architecture where interactive components are isolated in otherwise static HTML. RSC is islands by default.

Caching

Term Definition
SWR (HTTP) stale-while-revalidate — serve stale immediately, refresh in the background.
Surrogate key A tag attached to a cached response, allowing precise purging across many URLs.
Soft purge Marking a cache entry stale rather than deleting it, avoiding an origin stampede.
Stampede Many concurrent requests missing the same expired cache entry and all hitting the origin.
Single flight Ensuring only one computation runs per key, with others waiting for its result.
Request memoization Deduplicating identical calls within one render pass (React cache()).
Data Cache Next.js's cross‑request cache for fetch results.
Full Route Cache Next.js's server‑side cache of rendered HTML + RSC payload.
Router Cache Next.js's in‑memory client cache of visited routes' RSC payloads.
bfcache Back/forward cache — the browser storing a whole page in memory for instant back navigation.

Delivery

Term Definition
Preload scanner A browser subsystem that scans raw HTML ahead of the parser to start fetching subresources early. It cannot see JS‑computed URLs.
Critical path The chain of resources required before first render.
Render‑blocking A resource the browser waits for before painting (typically CSS in <head>).
Parser‑blocking A resource that halts HTML parsing (a plain <script src>).
Early Hints A 103 response with Link headers, sent before the real response, to start critical fetches during server think time.
Priority Hints fetchpriority="high"/"low" — telling the browser what matters.
Speculation Rules A browser API for declarative prefetching and prerendering of likely next pages.
Client hints Request headers (Save-Data, Sec-CH-Device-Memory, ECT) describing device and network.

Practice

Term Definition
RUM Real User Monitoring — performance data from actual users.
CrUX Chrome User Experience Report — public field data from opted‑in Chrome users, 28‑day window.
Synthetic Automated tests against a live site on a schedule.
Performance budget A hard limit on a metric or resource, enforced in CI.
Ratchet A gate that allows improvement but blocks regression, auto‑updating its baseline downward.
Facade A lightweight placeholder that loads a heavy widget only on interaction.
Load shedding Deliberately disabling non‑essential features under load.

Tooling reference

Field measurement

Tool Use for Notes
web-vitals (attribution build) Collecting field vitals with sub‑part breakdowns The foundation of everything
CrUX API / BigQuery Public benchmarking, competitor comparison 28‑day lag, Chrome only
PageSpeed Insights Field + lab in one view Good for a quick check, not for daily work
Search Console CWV by URL group, indexation impact Slow to update

Lab measurement

Tool Use for Notes
Chrome DevTools Performance Millisecond‑level main‑thread analysis Always throttle CPU 4–6×
DevTools Coverage Unused CSS/JS per page Points at splitting opportunities
DevTools Memory Heap snapshots, leak hunting Compare snapshots after N cycles
DevTools Rendering Layout Shift Regions, paint flashing Fastest CLS diagnosis
React DevTools Profiler Which components rendered and why Enable "record why each rendered"
Lighthouse CLI Reproducible lab scores + diagnostics Median of 5, never a single run
WebPageTest Real devices, request blocking, filmstrips Best tool for pricing third parties
@next/bundle-analyzer Bundle composition treemap Read client.html, gzipped mode

Testing & CI

Tool Use for
Playwright Interaction latency, CLS, memory, journey tests
Lighthouse CI Assertions on lab metrics and diagnostics
k6 / autocannon Load testing, stampede testing
size-limit Alternative bundle budgeting
react-compiler-healthcheck Compiler bail‑out rate
depcheck Unused dependencies
npm-why Who pulls in a transitive dependency
glyphhanger Font subsetting from real page content
fontpie Computing size-adjust fallback metrics

Useful commands

# Bundle analysis
ANALYZE=true npm run build

# Lighthouse, median of 5
for i in $(seq 1 5); do
  npx lighthouse "$URL" --quiet --output=json --output-path="./lh-$i.json" \
    --chrome-flags="--headless=new"
done
jq -s 'map(.audits["largest-contentful-paint"].numericValue) | sort | .[2]' lh-*.json

# Is streaming actually working in production?
curl -N -s -o /dev/null -w 'ttfb: %{time_starttransfer}s total: %{time_total}s\n' "$URL"

# Compression + cache headers
curl -sI -H 'Accept-Encoding: br, gzip, zstd' "$URL" \
  | grep -iE 'content-encoding|cache-control|age|x-cache|x-nextjs-cache'

# Is the LCP image in the HTML?
curl -s "$URL" | grep -o 'images\.[^"]*' | head

# Cache key fragmentation check
curl -sI "$URL" | grep -i age
curl -sI "$URL?utm_source=test" | grep -i age

# RSC payload size
curl -s "$URL" -H 'RSC: 1' -H 'Accept-Encoding: br' | wc -c

# Client boundary census
rg -l "^'use client'" app components | wc -l

# Find fetches with no explicit cache intent
rg -n 'fetch\(' app lib | rg -v "cache:|next:\s*\{"

# Find effect-based data fetching (Server Component candidates)
rg -n 'useEffect' app components | rg -i 'fetch|axios'

# Find missing cleanup
rg -n "addEventListener" app components | rg -v "removeEventListener"

# Route rendering modes
npx next build | grep -E '^[├└┌]'

Browser console snippets

// Image waste audit
[...document.images].filter(i => i.naturalWidth > 0).map(i => ({
  src: i.currentSrc.split('/').pop().slice(0, 40),
  intrinsic: i.naturalWidth,
  needed: Math.round(i.getBoundingClientRect().width * devicePixelRatio),
  waste: +(i.naturalWidth / (i.getBoundingClientRect().width * devicePixelRatio)).toFixed(2),
})).filter(r => r.waste > 1.5).sort((a, b) => b.waste - a.waste);

// What is the LCP element?
new PerformanceObserver(l => {
  const e = l.getEntries().at(-1);
  console.log('LCP:', e.element, e.size, e.url, e.renderTime);
}).observe({ type: 'largest-contentful-paint', buffered: true });

// Every layout shift, with its sources
new PerformanceObserver(l => {
  for (const e of l.getEntries()) {
    if (!e.hadRecentInput) console.log('shift', e.value.toFixed(4), e.sources?.map(s => s.node));
  }
}).observe({ type: 'layout-shift', buffered: true });

// Long tasks, live
new PerformanceObserver(l => {
  for (const e of l.getEntries()) console.log('long task', Math.round(e.duration), 'ms');
}).observe({ type: 'longtask', buffered: true });

// Which scripts are causing long frames?
new PerformanceObserver(l => {
  for (const e of l.getEntries()) {
    console.log('LoAF', Math.round(e.duration), 'ms',
      e.scripts?.map(s => `${new URL(s.sourceURL, location.href).hostname} ${Math.round(s.duration)}ms`));
  }
}).observe({ type: 'long-animation-frame', buffered: true });

// DOM size
document.querySelectorAll('*').length;

// Was this page prerendered?
performance.getEntriesByType('navigation')[0].activationStart > 0;

Topic Where
Core Web Vitals definitions and thresholds web.dev/vitals
web-vitals library github.com/GoogleChrome/web-vitals
Next.js caching documentation nextjs.org/docs — check your exact minor version
React Compiler react.dev/learn/react-compiler
Chrome DevTools performance features developer.chrome.com/docs/devtools
Speculation Rules API developer.chrome.com/docs/web-platform/prerender-pages
CrUX dataset developer.chrome.com/docs/crux

Version‑sensitive areas — always verify against the docs for your exact version rather than from memory or from this course: Next.js caching defaults, PPR / Cache Components APIs, the middleware/proxy file convention, and Speculation Rules browser support.


Course index

Module Topic
0 Orientation: reference app, impact/effort matrix
1 Foundations: business case, load anatomy, CWV, measurement, budgets
2 Quick wins: images, fonts, third parties, delivery, CSS
3 Rendering: modes, RSC boundaries, streaming, caching, ISR, PPR, middleware
4 JavaScript: analysis, splitting, dependencies, hydration
5 React runtime: profiling, memoization, state, lists, concurrency, forms
6 Vitals playbooks: LCP, INP, CLS, TTFB
7 Data: waterfalls, cache architecture, search, checkout
8 Advanced: speculation, workers, bfcache, memory, experiments, infra
9 Operating: RUM, CI gates, triage, practice
10 Page playbooks: home, PLP, PDP, search, checkout, mobile
A · B · C · D Appendix