6 November 2026 · 12 min read · BlitzHash · Performance

Core Web Vitals for Next.js: the first three fixes for vibe-coded apps

Short answer: for Core Web Vitals on a Next.js app that AI helped you build, fix three things first — identify the real Largest Contentful Paint (LCP) element and load it early with next/image (never lazy-load the hero), reserve space for every image and font so Cumulative Layout Shift (CLS) stays low, and shrink the JavaScript that runs on every click so Interaction to Next Paint (INP) stays under 200 ms. Google's thresholds, measured at the 75th percentile of real visits, are LCP under 2.5 seconds, INP under 200 milliseconds, and CLS under 0.1. If your app already feels sluggish for customers, our launch-ready check reviews speed alongside security, privacy, scaling and the bill.

This guide is for founders who shipped with Lovable, Bolt, Cursor, Replit or v0 onto a Next.js + Vercel stack, and now see "Needs improvement" in Search Console or PageSpeed Insights — or just feel the page jump and lag when people tap buttons.

What Core Web Vitals actually measure

Core Web Vitals are Google's three field metrics for real user experience. According to web.dev's Web Vitals overview (updated October 31, 2024), the stable set is:

  • LCP (Largest Contentful Paint): how quickly the main content appears. Good is 2.5 seconds or less.
  • INP (Interaction to Next Paint): how quickly the page responds after a tap, click or keypress. Good is 200 milliseconds or less. INP replaced First Input Delay as a Core Web Vital in 2024.
  • CLS (Cumulative Layout Shift): how much the layout jumps while things load. Good is 0.1 or less.

You pass when all three hit those targets for at least 75% of visits, split by mobile and desktop. Lab tools (Lighthouse on your laptop) are useful for debugging. Field data (Chrome User Experience Report in PageSpeed Insights or Search Console) is what Google uses for the report that matters.

Why vibe-coded Next.js apps struggle with Core Web Vitals

AI builders are great at screens. They are less careful about what the browser has to download and run before a person can read or click. Patterns we see again and again:

1. A hero image added as a plain ` without width and height, or with loading="lazy" on the thing above the fold. 2. A page marked "use client"` at the top so the whole tree ships to the browser, including charts and editors nobody needs on first paint. 3. Cookie banners, chat widgets and analytics scripts that push content down after paint. 4. Fonts loaded from a third-party CSS file with no size-adjust, so text reflows when the webfont arrives. 5. Client-side data fetching for the main heading, so LCP waits on JavaScript instead of arriving in the HTML.

None of that means you have to rewrite the product. It means you run a short triage, then apply the three fixes below.

What we measured on our own Next.js site

Before giving advice, we inspected blitzhash.com (Next.js on Vercel) with curl on November 6, 2026. This is HTML and header data, not a lab Lighthouse score — Google's public PageSpeed API was rate-limited from this environment that morning — but it shows the same signals founders can check without a performance engineer.

  • The homepage HTML is about 117 KB. The /check money page is about 71 KB.
  • From our measurement region, Time to First Byte (TTFB) for the homepage was about 0.86 seconds end-to-end (curl time_starttransfer), with the response marked x-vercel-cache: HIT and x-nextjs-prerender: 1.
  • The homepage has 16 `` tags. Every one already has both width and height attributes — the CLS-friendly pattern Next.js documents for next/image.
  • 15 of 16 images use loading="lazy". The logo uses loading="eager" with fetchPriority="low" and sizes="64px". That is the right instinct for a small brand mark; the LCP element is usually a hero image or a large heading, not the logo.
  • Response Link headers preload two self-hosted woff2 fonts (about 23 KB and 29 KB), which matches the next/font pattern of shipping fonts from your own origin instead of waiting on Google Fonts CSS.
  • The Content-Security-Policy allows https://vitals.vercel-insights.com, so the project is already wired to send vitals somewhere — useful when you add useReportWebVitals later.
  • There are 47 `` opening tags in the homepage HTML (including framework chunks). That is normal for a modern Next app, and it is also why INP work starts with "ship less client JavaScript," not with micro-optimizing one button.

Use those numbers as a template for your own site: count images with dimensions, find anything above the fold that is still lazy, check whether fonts are preloaded from your origin, and note TTFB before you rewrite components.

Core Web Vitals for Next.js: the 20-minute triage

Do this once on your live production URL (not only on localhost). Write the numbers down so you can see whether the three fixes helped.

Step 1: Open PageSpeed Insights on your real URL

Go to PageSpeed Insights, paste your production URL, and run it for mobile. If "Discover what your real users are experiencing" shows data, trust that section first. Lab scores below it are a diagnosis aid, not the final grade. Search Console's Core Web Vitals report groups URLs the same way once you have enough traffic.

Step 2: Name the LCP element

In Chrome, open DevTools → Performance, start recording, reload, stop, and look for the LCP marker. Or in PageSpeed Insights, open the Largest Contentful Paint element diagnostic. Write down whether it is:

  • a hero image,
  • a large heading in a webfont, or
  • a background image set in CSS (hardest, because the browser cannot see it in the HTML).

web.dev's Optimize LCP guide (updated March 31, 2025) is blunt: most of the win comes from discovering that resource early and giving it priority — not from compressing it a second time after JavaScript has already delayed it.

Step 3: Watch one interaction for INP

On a mid-range phone or Chrome's CPU throttling, open your heaviest screen (dashboard, editor, pricing calculator). Tap the primary button. If the UI freezes before paint, you have an INP problem even if the page "loads fast." Lighthouse cannot fully measure INP without a user; Total Blocking Time in the lab is only a proxy.

Step 4: Film the first two seconds for CLS

Record the first load with your phone camera or DevTools. If a cookie banner, announcement bar or late image pushes the heading down, that is CLS. Next.js's image component reserves space when width and height are set; late-injected UI often does not.

Fix 1: Get LCP under 2.5 seconds

Use next/image for the real LCP image — and never lazy-load it

Next.js documents that the Image component provides size optimization, visual stability and lazy loading by default. For the one above-the-fold LCP image, override the defaults:

import Image from 'next/image'
import hero from './hero.png'

export function Hero() {
  return (
    
  )
}

priority tells Next to preload the image. Do not put priority on every image — web.dev notes that fetch-priority hints stop helping when everything is high priority. Remote images need explicit width and height (or fill inside a sized parent) because Next cannot read remote dimensions at build time.

AI-builder prompt you can paste: "Find the largest above-the-fold image on the home page. Convert it to next/image with the priority prop, correct width and height, and a sizes attribute that matches how wide it actually displays on phones. Remove loading=lazy from that image only."

Prefer server-rendered content for the LCP text

If your LCP element is a heading that appears only after a client fetch, move that data into a Server Component so the HTML arrives with the text. Client-side rendering of the main headline is one of the classic LCP delays in AI-generated apps.

Keep fonts on your origin

Use next/font so fonts self-host and preload. Our homepage's Link preload headers for two woff2 files are exactly that pattern. Avoid a render-blocking Google Fonts CSS chain when the LCP element is text.

Watch TTFB

If TTFB alone is already near 2.5 seconds, no frontend trick will save LCP. Fix redirects, region mismatch, and uncached origin work first. Our own cached homepage TTFB under a second is the shape you want; a cold origin with many redirects is not.

Fix 2: Keep CLS under 0.1

Always set dimensions (or use next/image)

Unset images start at height 0 and shove content down when they load. On our homepage, all 16 images already declare width and height — keep that habit when you add new screenshots from Lovable or Bolt exports. For remote URLs, pass width and height manually.

Reserve space for banners and embeds

Cookie notices, Calendly embeds, chat bubbles and A/B banners should either overlay content or sit in a reserved box with a fixed min-height. Never insert a tall bar above content the user is already reading unless they clicked something.

Match font metrics

next/font can adjust fallback metrics so text does not jump when the webfont swaps in. If you still load fonts by hand, set font-display: swap and avoid late @font-face rules discovered only after CSS arrives.

Skeletons that match final height

Loading skeletons that are shorter than the real card cause a second shift when data arrives. Size the placeholder like the finished block.

Fix 3: Get INP under 200 ms

INP is a main-thread problem. A site can paint the hero quickly and still fail when someone taps "Generate" or opens a filter.

Push "use client" to the leaves

Default to Server Components. Put "use client" only on the interactive leaf (the button, the form, the chart), not on the whole page. A page that starts with "use client" ships its entire tree for hydration.

Lazy-load heavy widgets

Charts, rich-text editors, PDF viewers and big date pickers belong behind next/dynamic so they load when needed:

import dynamic from 'next/dynamic'

const HeavyChart = dynamic(() => import('./HeavyChart'), {
  ssr: false,
  loading: () => Loading chart…,
})

Give instant feedback on expensive updates

Use useTransition for state that re-renders a big list so the press paints immediately while the heavy work continues. Break long loops into chunks, or move parsing to a worker.

Audit third-party scripts

Load analytics, chat and heatmaps with next/script and strategy="afterInteractive" or lazyOnload. Turn one off in a test deploy and re-check INP — founders are often surprised which widget owns the main thread.

AI-builder prompt you can paste: "List every file with 'use client' at the top. Move that directive to the smallest child that needs hooks or browser APIs. Dynamic-import any chart, editor or map that is not visible on first paint."

Downloadable-free checklist (print or copy)

Mark each item ☐ Pass / ☐ Fail / ☐ Not sure. "Not sure" counts as fail until you check.

Measure

  • ☐ PageSpeed Insights (or Search Console) run on the production URL, mobile view saved
  • ☐ LCP element identified (image / heading / CSS background)
  • ☐ One primary tap timed on a phone or with CPU throttle
  • ☐ First-load recording checked for layout jumps

LCP

  • ☐ Above-the-fold LCP image uses next/image with priority (not lazy)
  • ☐ sizes matches real display width on phones
  • ☐ Main heading HTML arrives from the server, not a client fetch
  • ☐ Fonts self-hosted or preloaded from your origin
  • ☐ TTFB checked; no chain of marketing redirects into the app

CLS

  • ☐ Every image has width and height (or fill in a sized parent)
  • ☐ Cookie / announce banners reserved or overlaid
  • ☐ Embeds (calendars, videos) have a fixed min-height box
  • ☐ Skeleton loaders match final card height

INP

  • ☐ "use client" only on interactive leaves
  • ☐ Heavy widgets behind next/dynamic
  • ☐ Primary buttons show immediate feedback on press
  • ☐ Third-party scripts deferred; unused ones removed

Ship

  • ☐ Re-run PageSpeed Insights after the three fixes
  • ☐ Note field data in a week (CrUX lags) before declaring victory

How this ties to launch readiness

Speed is one lane of "ready for customers." A fast page that leaks data still fails. Pair this Core Web Vitals work with:

For day-to-day engineering habits (reviews, CI, production gates), our open Senior Engineer Skills repo is a Cursor-oriented checklist you can drop into an AI coding workflow — useful when the same agent that built the UI is also the one that should stop shipping layout-shift heroes.

FAQ

Do Core Web Vitals affect Google ranking for my SaaS landing page?

Google has said Core Web Vitals are part of its page experience signals. They are not the only ranking factor, and a useful product still needs links and intent match. Treat a "Poor" report as a customer-experience bug first; search is a side benefit of fixing it.

Lab score is green but Search Console says Needs improvement. Which do I trust?

Trust the field data. Lab tests run on a fixed device and network. Your real visitors use mid-range phones on flaky LTE. Optimize for the 75th percentile in CrUX / Search Console, then use Lighthouse to find the cause.

My app is mostly a logged-in dashboard. Do Core Web Vitals still matter?

Yes for marketing and signup pages that Google indexes, and yes for retention on the dashboard — INP especially. CrUX mainly reflects public URLs with enough Chrome traffic; instrument useReportWebVitals from next/web-vitals for private screens so you still see LCP/INP/CLS from real sessions.

Will moving off Vercel fix Core Web Vitals?

Usually no. Hosting changes TTFB and edge distance. Most vibe-coded failures we see are image discovery, client JavaScript weight and late banners — the same on any host. Fix those first; then compare bills with a Vercel bill review if cost is the separate problem.

Book a free technical assessment

If you want a senior pass over speed, security and launch readiness together — not a generic Lighthouse PDF — book a free technical assessment or start with the launch-ready check. Bring your production URL and, if you have it, the PageSpeed Insights link. We will tell you which of LCP, INP or CLS is actually costing you customers, and what to change first.

Sources

Related posts

Next step

Book a free 15-min launch review.

A short video call. We look at your AI-built app, flag the biggest risks in security, launch readiness, speed and cost, and you leave with next steps. No obligation.

Every price is a custom quote after we look at the app. No work starts until you accept the proposal.