CodeDevlify LogoCodeDevlify
All articles
Performance

Core Web Vitals Without the Headache

The four front-end decisions that move LCP, INP, and CLS more than any amount of micro-optimisation — with the measurements that tell you whether they worked.

CodeDevlify Editorial

Product & Platform team

7 min read
Three performance gauges labelled LCP, INP and CLS sitting in the green.

Most performance advice is a list of forty things. In practice four decisions account for nearly all of the movement, and the rest is noise until those four are right.

MetricWhat it measuresGoodUsual culprit
LCPTime to the largest visible element≤ 2.5sAn unoptimised hero image
INPResponsiveness to input≤ 200msToo much JavaScript on the main thread
CLSUnexpected layout movement≤ 0.1Images and ads without reserved space

1. Give every image a size

This is the cheapest fix in web performance and it lands on two metrics at once: the browser reserves the box (CLS) and can prioritise the right file (LCP). If you're on Next.js, next/image does it for you as long as you actually pass the dimensions.

TSX
<Image  src="/blog/hero.jpg"  alt="A dashboard showing site analytics"  width={1200}  height={630}  priority                                   // only on the LCP image  sizes="(min-width: 1024px) 720px, 100vw"   // stops over-large downloads on phones/>

2. Load fonts without a flash

A web font that arrives after first paint reflows your entire text column. Self-host the font, subset it to the characters you use, and set font-display: swap with a metrics-matched fallback so the swap doesn't shift anything.

CSS
@font-face {  font-family: "Inter";  src: url("/fonts/inter-subset.woff2") format("woff2");  font-display: swap;  /* Matched to the fallback so swapping in doesn't move a single line. */  size-adjust: 107%;  ascent-override: 90%;}

3. Ship less JavaScript to the client

INP is almost entirely a main-thread problem. The fix is not faster code; it's absent code. Render on the server, and let only genuinely interactive leaves become client components — a copy button, a filter, a menu.

  • Push "use client" as far down the tree as it will go — a client component drags its whole subtree with it.
  • Import icons and utilities individually so the bundler can drop the rest.
  • Defer third-party scripts (chat widgets, analytics) to lazyOnload; none of them need to run before your content does.

4. Measure the field, not your laptop

Lighthouse on a wired connection is a debugging tool, not a score. What ranks is field data from real devices. Run the lab test to find the cause, but confirm the fix against real users.

Shell
# Lab: reproducible, good for A/B-ing a changenpx unlighthouse --site https://example.com # Field: what actually counts# PageSpeed Insights → "Discover what your real users are experiencing"
performancelcpinpclsimagesfonts
ShareXLinkedIn

Keep reading

Engineering

Anatomy of a 30-Second Site Provision

What actually happens between clicking “Create site” and a live HTTPS URL — the gRPC call, the container, the DNS wait, and the four places we had to stop blocking the request.

11 min read

New posts, roughly twice a month

Engineering write-ups, performance notes, and what we learned running the platform. No product announcements dressed up as articles.

Unsubscribe in one click. We never share your address.