Forge
Web performance

Why your site is slow: Core Web Vitals problems you can find in code

Core Web Vitals measure loading (LCP, good under 2.5 s), responsiveness (INP, under 200 ms) and visual stability (CLS, under 0.1). Most bad scores trace back to a few code decisions: an unoptimised hero image, fonts and scripts that block rendering, a large client bundle, unsized media and slow data fetching on the server.

Last reviewed by the Forge team

What goes wrong

What it costs when this is missed

High

Visitors leave

Every extra second before the page shows something loses people, on mobile most of all.

High

Slow server responses

Queries in loops and uncached pages make every visit wait for the database before anything can render.

Medium

Weaker rankings

Core Web Vitals are part of Google's page experience signals. Between similar pages, the faster one has the edge.

Medium

Pages that jump

Layout shift makes people tap the wrong thing, and it counts against you in CLS.

Common problems

What to look for in your code

Each one: why it hurts, and how to spot it in your own project.

01An unoptimised hero image

The largest image above the fold is usually what LCP measures. A 3 MB PNG, or one the browser finds late, delays it.

How to spot it: Check the hero image's size and format, and that it's preloaded or marked as priority.

Risky
<img src="/hero.png" />  <!-- 2,400 px wide, 3.1 MB -->
Better
<Image src={hero} alt="…" priority sizes="(max-width: 768px) 100vw, 50vw" />

02Lazy-loading the image that matters

loading="lazy" on the hero image tells the browser to wait, which is exactly wrong for the LCP element.

How to spot it: Search for loading="lazy" on images in hero sections and page headers.

03Render-blocking scripts and fonts

Analytics, chat widgets and tag managers in <head>, and fonts loaded without font-display, hold the first paint back.

How to spot it: Look at your layout's <head>: third-party scripts should load after the page (async, defer or the framework's lazy strategy), and fonts should be self-hosted with font-display: swap.

04A large client bundle

Marking whole pages as client components, or importing heavy libraries for one function, ships JavaScript every visitor must download and run.

How to spot it: Run your bundler's analyser. Look for 'use client' at the top of pages and layouts, and for large libraries used once.

Risky
"use client"; // the whole page, for one dropdown
import moment from "moment";
Better
// the page renders on the server; only the dropdown is a client component
import { Dropdown } from "./Dropdown";

05Media without dimensions

Images, video and embeds without width and height push content down as they load. That's what CLS measures.

How to spot it: Look for <img>, <video> and <iframe> tags without width and height, or without a fixed aspect ratio.

06Long tasks in event handlers

Heavy work on click or input (filtering big lists, re-rendering everything) blocks the main thread, which INP measures.

How to spot it: Profile a slow interaction in the browser's Performance panel, then find the handler that runs during it.

07Queries in loops

Fetching related rows one by one (the N+1 problem) turns one page load into hundreds of database round trips.

How to spot it: Look for awaits inside loops over query results, and for list endpoints without pagination.

Risky
for (const order of orders) {
  order.customer = await db.customer.find(order.customerId);
}
Better
const orders = await db.order.findMany({ include: { customer: true }, take: 50 });

08Nothing cached

Pages that could be static are rebuilt on every request, so every visitor waits for the server.

How to spot it: Check your framework's build output for which routes are static and which are rendered per request, and why.

Quick self-check

How does your project do?

Tick each one that's true today. Anything left unticked is worth a closer look.

Tick what's true for your project. 8 checks.

How Forge checks this

A second opinion on your code, from the SEO and Issues scans.

  • The SEO scan looks for Core Web Vitals risks in your layouts, images, fonts and third-party scripts.
  • The Issues scan finds N+1 queries, unbounded lists and heavy work on request paths.
  • Both point at the exact files, so you fix causes rather than chase scores.

Questions

Lab data or field data?

Lighthouse is a lab test on one simulated device. Google ranks on field data from real Chrome users (CrUX), at the 75th percentile. Use the lab to find causes and the field to confirm the fix.

Do Core Web Vitals affect rankings?

They're part of Google's page experience signals. Relevance matters more, but between similar pages the faster one has the edge, and visitors leave slow pages either way.

Can a code review find performance problems?

Many, yes: the causes are in the code (image setup, script loading, queries in loops). Measuring then tells you which ones matter most.

Related guides

All guides

Sources