- Published on
Performance & Core Web Vitals 2025 — LCP, CLS, INP, RUM, Image/Font/JS Optimization, Edge, CDN, HTTP/3 (S6 E6)
- Authors

- Name
- Youngju Kim
- @fjvbn20031
Prologue — performance is not a feature
A common misconception: "performance optimization is post-launch tuning." In 2025, reality says otherwise.
- Google search ranking incorporates Core Web Vitals (since 2021).
- Ecommerce research: +1% conversion per 0.1s LCP improvement (Amazon, Booking).
- INP became an official metric in 2024, kicking off a responsiveness race.
- Korean users live on subway 5G, low-power mode — the tail matters.
"Performance isn't a feature. It's the precondition for every feature."
Good AI, good UX, great motion — all worthless if slow. This is the 2025 frontline guide.
1. Core Web Vitals 2025 — the three numbers
LCP (Largest Contentful Paint)
- When the largest viewport element renders.
- Good ≤ 2.5s, Needs Improvement ≤ 4s, Poor > 4s.
- Usually a hero image or text block.
CLS (Cumulative Layout Shift)
- Cumulative viewport shift score.
- Good ≤ 0.1, Needs ≤ 0.25, Poor > 0.25.
- Usual offenders: images without dimensions, ads, font swap.
INP (Interaction to Next Paint) — replaced FID in 2024
- From input to next paint.
- Good ≤ 200ms, Needs ≤ 500ms, Poor > 500ms.
- Detects slow JS and main-thread blocking; covers the entire page lifetime (unlike FID).
Measurement conventions
- p75 percentile — matches most-user experience.
- Real users, 28-day rolling (CrUX).
- Mobile vs desktop split.
Supporting metrics
- FCP target 1.8s, TTFB target 0.8s.
- TTI is legacy — INP replaced it.
2. RUM vs synthetic — what to measure
Synthetic
- Controlled lab (Lighthouse, WebPageTest, SpeedCurve).
- Pros: reproducible, regression detection.
- Cons: diverges from real users.
RUM
- Real browsers (Vercel Speed Insights, Datadog RUM, New Relic, Sentry, CrUX).
- Pros: truth.
- Cons: noisy, outliers dominate small samples.
Do both
- Lighthouse in CI for regressions.
- RUM in production for truth.
- CrUX monthly review for competitive benchmarking.
CrUX (Chrome UX Report)
Anonymized Chrome opt-in data, monthly aggregate. Powers PageSpeed Insights and is available in BigQuery.
3. Critical rendering path
Browser pipeline: Network → Parse HTML → CSSOM → Render Tree → Layout → Paint → Composite.
Common bottlenecks
- Render-blocking CSS.
- Render-blocking JS.
- Font swap period (FOIT/FOUT).
2025 standard techniques
- Critical CSS inlined for above-the-fold.
<script defer>/async— stop blocking HTML parse.<img fetchpriority="high">on the LCP image.<link rel="preconnect">for third-party origins.<link rel="preload">for critical fonts/hero images.
4. JS bundle diet
Good sizes in 2025:
- Initial < 170kb gzipped, per route < 50kb.
- Mobile parse/execute cost is real.
Bundler landscape
- esbuild (Go), swc (Rust, inside Next.js), Rollup (libraries), Turbopack (Next 15 default), Vite (Rollup underneath), Rspack (Rust, Webpack-compatible), Bun (runtime + bundler).
Usual offenders
moment→date-fnsordayjs.lodashfull → per-function import.react-icons→ raw SVG.- CommonJS packages that block tree-shaking — mark
"sideEffects": false. - Dynamic import for heavy widgets (charts, modals).
- Polyfill bloat — target Baseline 2024.
- Runtime CSS-in-JS → zero-runtime (Linaria, Vanilla Extract, Pigment) or Tailwind / CSS Modules.
5. Image optimization — the LCP lever
Format
- AVIF (best compression) + WebP + JPEG fallback. SVG for vectors.
Responsive <picture> and <img srcset sizes>
Next.js <Image>
import Image from 'next/image'
<Image src="/hero.jpg" width={1200} height={600} priority placeholder="blur" blurDataURL={blur} alt="Hero" />
Auto AVIF/WebP, responsive srcset, lazy by default (priority for LCP), prevents CLS.
Tips
- Always specify
width/height. - Lazy + priority combo.
- LCP image: preload +
fetchpriority="high". - Hero art worth inlining as SVG/data-URL for small files.
6. Font optimization
font-display
swap— fallback first (fast, CLS risk).optional— if not loaded in 100ms, keep fallback (no CLS).fallback— in between.
size-adjust + ascent-override
Match fallback metrics to web font — dramatically reduces CLS.
Subsetting
Korean/Japanese/Chinese fonts are multi-MB. Subset to KS X 1001 2,350 / JIS core / etc. Use Subfont or Glyphhanger to automate.
Variable fonts
One file, every weight/width. Pretendard Variable (Korean), Inter/Geist (Latin).
Recommended stack (Korean)
Pretendard Variable + Noto Sans KR fallback, font-display: swap, size-adjust on fallback.
7. Caching
HTTP cache
Cache-Control: public, max-age=31536000, immutablefor hashed assets.no-cachefor always-validate.no-storenever.- ETag / Last-Modified for conditional requests.
- stale-while-revalidate for smooth rotation.
Next.js 15 caching (redesigned)
Request memoization, Data Cache, Full Route Cache, Router Cache. 2025+: explicit use cache directive opts in.
Service Worker
Offline, app-shell, cache-first for assets (Workbox). PWA revival on iOS as restrictions ease.
Edge caching
CDN-level stale-while-revalidate. ISR remains the Next.js cornerstone.
8. Edge, CDN, HTTP/3
Roles
Geographic proximity, origin offload, TLS/HTTP/3/compression.
Players
Cloudflare (best balance), Vercel Edge, Fastly (VCL), AWS CloudFront, Netlify Edge. Korea: Toast KRP, NAVER Cloud CDN, KT Olleh CDN.
Edge functions
Cloudflare Workers, Vercel Edge, Deno Deploy, Fastly Compute@Edge. Minimal cold start (V8 isolates). Use for A/B, auth, rate limit, i18n routing.
HTTP/3 (QUIC)
UDP, no head-of-line blocking, 0-RTT, TLS 1.3. Default on most CDNs. Huge win on mobile and unstable networks — especially Korean subway 5G.
9. INP optimization
Long tasks (>50ms) on the main thread break responsiveness.
- Debounce / throttle search and scroll handlers.
- Scheduler API:
scheduler.postTask(() => heavy(), { priority: 'background' }). useDeferredValue/useTransitionin React 18+.- Web Workers for heavy computation.
- Virtualization (
react-window, TanStack Virtual) for long lists. - Code splitting for features used occasionally.
Measure with Chrome DevTools Performance → INP, Long Task API in production.
10. Tooling
- Vercel Speed Insights — zero-config RUM on Vercel.
- Datadog RUM / New Relic — enterprise-grade.
- CrUX Dashboard — free, origin-level.
- PageSpeed Insights — Lighthouse + CrUX combined.
- WebPageTest — highest-fidelity synthetic.
11. Practical checklist
Project setup
- Framework Image component,
font-display: swap+size-adjust, Critical CSS. - Bundle Analyzer, Lighthouse CI with thresholds (
LCP<2.5s,CLS<0.1,INP<200ms). - RUM (Vercel Speed Insights or self-hosted).
Pre-release
- LCP cause analysis (DevTools Performance insights), INP handler review, image dimensions, bundle under target, font preload, 3G Fast emulation.
Post-release
- RUM p75 trends, incident rollback, weekly performance review.
12. Advanced patterns (2025)
- Partial Pre-Rendering (PPR) — Next.js 15 static shell + dynamic holes.
- Islands — Astro: static + JS islands only.
- Qwik resumability — near-zero initial JS.
- Bun / Deno — faster startup for SSR.
- Turbopack — Next.js 15 default.
- Server streaming with RSC + Suspense.
12-item checklist
- CWV p75 tracked via RUM?
LCP<2.5s,CLS<0.1,INP<200msat p75?- LCP image has priority +
fetchpriority="high"? - All images have explicit
width/height? - Fonts use
font-display+size-adjust? - Initial bundle < 170kb, route < 50kb?
- Dynamic import for heavy code?
- CDN + edge caching configured?
- HTTP/3 enabled?
- Lighthouse CI catches regressions?
- RUM operated in production?
- Korean mobile/subway network tested?
10 anti-patterns
- Shipping without measuring real users.
- Optimizing for Lighthouse score but not p75 RUM.
- Unsized images (CLS bomb).
font-display: block(FOIT hides content).- Giant moment.js / lodash full imports.
- Runtime CSS-in-JS in hot paths.
- Forgetting
<link rel="preload">on LCP image. - Treating INP like FID (single-interaction testing).
- Sampling RUM too low to detect tail regressions.
- Ignoring Asian/Korean network realities.
Next episode
Season 6 Episode 7: Accessibility & Internationalization 2025 — WCAG 2.2, EU Accessibility Act, ARIA, next-intl, Korean/Japanese typography, RTL.
"A fast product is a good product. A slow product is a non-existent product."
— End of Performance & Core Web Vitals.