Skip to main content
</>Rosecraft Studios
performanceweb-developmentseonext-js

Web Performance: A Practical Guide to Core Web Vitals

5 min read

Why Core Web Vitals Matter

Google's Core Web Vitals aren't just abstract metrics — they directly impact your search rankings, user engagement, and conversion rates. A study by Deloitte found that a 0.1-second improvement in mobile site speed increased conversion rates by 8.4% for retail sites and 10.1% for travel sites.

At Rosecraft Studios, every project ships with a Lighthouse Performance score of 95 or higher. Here's how we consistently achieve that.

The Three Metrics That Matter

Largest Contentful Paint (LCP)

Target: under 2.5 seconds

LCP measures how long it takes for the largest visible element (usually a hero image or heading) to render. It's the metric users "feel" most directly.

// Bad: Unoptimized hero image blocks LCP
<img src="/images/hero.png" alt="Hero" />

// Good: Optimized with next/image, priority loading
import Image from 'next/image';

<Image
  src="/images/hero.webp"
  alt="Hero section showcasing our engineering work"
  width={1200}
  height={630}
  priority
  sizes="100vw"
/>

Key strategies:

  1. Use priority on the LCP element — Tells Next.js to preload the image
  2. Serve modern formats — AVIF is 50% smaller than JPEG, WebP is 30% smaller
  3. Right-size images — Use sizes prop so the browser downloads the correct variant
  4. Minimize server response time — RSC + edge caching gets TTFB under 200ms
Run `npx web-vitals-cli https://your-site.com` to measure your current Core Web Vitals from the command line. It uses real Chromium and gives you the same data as Google's field metrics.

Interaction to Next Paint (INP)

Target: under 200 milliseconds

INP replaced First Input Delay (FID) in March 2024. It measures the latency of all interactions throughout the page's lifecycle, not just the first one.

The biggest INP killers:

  1. Long JavaScript tasks — Any task over 50ms blocks the main thread
  2. Hydration — Client-side React hydration re-renders the entire component tree
  3. Event handlers doing too much — Click handlers that trigger cascading state updates
// Bad: Heavy computation in click handler
function handleFilter(tag: string) {
  const filtered = allPosts
    .filter((p) => p.tags.includes(tag))
    .sort((a, b) => b.date - a.date)
    .map((p) => ({ ...p, excerpt: generateExcerpt(p.content) }));
  setFilteredPosts(filtered);
}

// Good: Memoize expensive computations, defer non-critical work
const filteredPosts = useMemo(
  () => allPosts.filter((p) => activeTag === 'all' || p.tags.includes(activeTag)),
  [allPosts, activeTag],
);
React Server Components are the single most effective tool for improving INP. Components that don't need interactivity should never ship JavaScript to the client. Every kilobyte of JS you remove is a potential INP improvement.

Cumulative Layout Shift (CLS)

Target: under 0.1

CLS measures visual stability. Every time an element shifts position after rendering, it contributes to the CLS score. Common offenders:

  1. Images without dimensions — The browser doesn't know how much space to reserve
  2. Fonts loading late — Text reflows when custom fonts replace system fonts
  3. Dynamic content injection — Ads, embeds, or lazy-loaded content pushing elements around
// Bad: Image causes layout shift
<img src="/photo.jpg" alt="Team photo" />

// Good: Explicit dimensions prevent shift
import Image from 'next/image';

<Image
  src="/photo.jpg"
  alt="Team photo"
  width={800}
  height={600}
  className="rounded-lg"
/>

For fonts, we self-host with next/font to eliminate Flash of Unstyled Text (FOUT):

import { Poppins, Inter } from 'next/font/google';

const poppins = Poppins({
  subsets: ['latin'],
  weight: ['600', '700', '800'],
  variable: '--font-heading',
  display: 'swap',
});

Our Performance Checklist

Every page we ship passes this checklist:

Images

  • All images use next/image with explicit width and height
  • Hero/LCP image has priority flag
  • Below-fold images use loading="lazy" (default in Next.js)
  • Format priority: AVIF, WebP, then PNG/JPEG fallback
  • No image exceeds 200 KB after optimization

JavaScript

  • Default to Server Components (zero client JS)
  • "use client" only for interactive components
  • Code-split heavy components with dynamic() imports
  • No unused dependencies in the bundle
  • Tree-shaking verified with @next/bundle-analyzer

CSS

  • Tailwind CSS purges unused utilities at build time
  • No render-blocking external stylesheets
  • Critical CSS inlined by Next.js automatically
  • Animations use transform and opacity only (GPU-composited)

Fonts

  • Self-hosted via next/font for zero layout shift
  • display: swap for progressive rendering
  • Only load weights actually used (not the full family)
  • Preload the primary heading font

Measuring in Production

Lab data (Lighthouse) is useful for development but doesn't capture real user experience. For production monitoring, we use:

// Report Web Vitals to your analytics
export function reportWebVitals(metric: NextWebVitalsMetric) {
  if (metric.label === 'web-vital') {
    analytics.track('Web Vital', {
      name: metric.name,
      value: Math.round(metric.value),
      rating: metric.rating,
    });
  }
}

Field data from Chrome User Experience Report (CrUX) is what Google actually uses for ranking signals. Monitor it monthly through Google Search Console.

Results From Our Projects

Project LCP INP CLS Lighthouse
SaaS Dashboard 1.1s 89ms 0.02 98
Marketing Site 0.8s 45ms 0.00 100
E-commerce 1.4s 120ms 0.03 96
Content Platform 1.2s 67ms 0.01 97

Every project exceeds Google's "Good" thresholds. The common thread: React Server Components for minimal JS, next/image for optimized media, and next/font for stable typography.

Is your site's performance holding back your search rankings? Schedule a performance audit and we'll identify exactly what's slowing you down and how to fix it.

Share this article

Corey Rosamond, Founder and Principal Engineer of Rosecraft Studios

Corey Rosamond

Founder & Principal Engineer

Learn more

Enjoyed this article?

Get notified when we publish new insights on web development and engineering.