Topic · 6 articles

Web performance

The four metrics that actually matter for user-facing web apps — and the engineering moves that move them in production.

Web performance is the topic where the gap between what tooling can measure and what users perceive is the largest. A 99th-percentile Lighthouse score is not the same as a fast-feeling site, and a site that feels fast to one user can score badly on the synthetic tests Google's bots run from a cold cache. The posts in this topic try to bridge that gap — to name the metrics that correlate with user perception, to explain how each one is measured in the real world, and to cover the engineering work that actually moves them.

The work splits into roughly four areas. The first is loading performance — the engineering that decides whether a page renders in 500ms or 4 seconds for a real user on a flaky mobile connection. The second is rendering performance — the work that decides whether interactions feel snappy or stuttery once the page is loaded. The third is hydration and JavaScript cost — the modern problem that did not exist before SPAs but now sits at the heart of most performance regressions. The fourth is measurement — the discipline of catching regressions before users feel them.

If you are new to web performance, start with the Core Web Vitals explainer and the bundle-size deep-dive — the metrics first, then the largest single lever. If you are already optimising production sites, the hydration-cost post and the real-user-monitoring guide are the natural follow-ups.

Covers:Largest Contentful Paint (LCP) and what drives itCumulative Layout Shift and font / image sizingInteraction to Next Paint (INP) and main-thread blockingJavaScript bundle splitting and lazy loadingReal-user monitoring vs synthetic testing
📖 Topic guide

Web performance: the four metrics, where they come from, and what moves them

Most performance work starts with a Lighthouse score and ends with a developer wondering why the score moved but users did not notice. This guide names the metrics that correlate with actual user experience, explains where each one comes from, and points at the deep-dives that cover the specific engineering moves to improve each.

01

The metrics that correlate with how users feel

Google's Core Web Vitals are the closest the industry has to a shared definition of "a fast site," and the reason they hold up is that each one was chosen specifically because it correlates with a measurable user behaviour — bounce rate, conversion, time on page. Largest Contentful Paint measures how long it takes the most prominent element in the viewport to render. Cumulative Layout Shift measures how much the page jumps around as it loads. Interaction to Next Paint measures how long the user waits between tapping something and seeing the result.

The three metrics map cleanly to three different parts of the work. LCP is mostly a loading problem: the HTML, the CSS, the hero image, the font that the hero text needs to render. CLS is mostly a layout problem: dimensions declared up front so the browser doesn't have to reshuffle when assets arrive. INP is mostly a JavaScript problem: long tasks blocking the main thread between the user's input and the browser's response.

There is a fourth metric most teams should also track even though Google doesn't grade on it directly — Time To First Byte. TTFB sits below everything else: a slow server response means LCP is bounded by the server, no matter how well the rest of the page is optimised. Most performance investigations that start at the frontend and move backward eventually find a TTFB problem hiding underneath.

02

Where load time actually goes

On a typical modern web page, the time between a user clicking a link and seeing meaningful content breaks down into four roughly equal slices for a cold visit: network transfer of the HTML, network transfer of critical CSS and JavaScript, browser parsing and rendering, and the hydration step where the JavaScript framework attaches event handlers and reconciles the static markup with its component tree.

Each slice has its own toolkit. Network transfer is reduced by edge caching, by compressing assets aggressively, and by bundling so that the critical path needs fewer round-trips. Parsing and rendering is reduced by smaller assets, fewer render-blocking scripts, and inlining the CSS that is needed before first paint. Hydration is reduced — and this is the area where the modern frameworks have shifted most rapidly — by sending less JavaScript in the first place, deferring non-critical components, and using streaming server rendering to overlap hydration with later network requests.

The deep-dives in this topic cover each of those areas individually. The bundle-size post covers the largest single lever for most teams: most production sites ship 3-5x more JavaScript than they need, and the simplest analysis with a bundle visualiser reveals which dependencies are responsible. The hydration-cost post covers the modern problem of an SPA that paints quickly and then locks up the main thread for 600ms while the framework attaches itself.

03

The hydration tax and how the modern frameworks address it

Hydration is the price you pay for client-side interactivity on top of a server-rendered page. The HTML arrives fast, the page paints fast, and then the JavaScript bundle has to load, parse, execute, attach event listeners, and reconcile its component tree with the markup the server already produced. On a fast laptop this is invisible. On a mid-range Android over a 4G connection it is the single largest source of perceived slowness for any SPA.

The frameworks have responded with three patterns. The first is islands architecture — the page is mostly static HTML, with only specific interactive components hydrating. The second is server components — the framework moves more work onto the server permanently, and only the components that actually need client-side state ship JavaScript. The third is selective and progressive hydration — the parts of the page the user is most likely to interact with first get hydrated first, and the rest hydrate as idle work in the background.

Which pattern fits depends on the application shape. A mostly-content site benefits enormously from islands. A heavily-interactive product app benefits more from server components plus careful streaming. A page that is two-thirds content and one-third interactive is the hardest case — none of the three patterns is a clean fit, and the right answer is usually some combination, applied with measurement at every step.

04

Synthetic tests vs real-user measurement

Lighthouse and PageSpeed Insights run a synthetic test from a Google datacenter on a throttled connection. The numbers are useful for catching regressions in a CI pipeline and for getting a baseline reading on a new page. They are not the numbers your actual users are seeing. A user on a fast home connection in Mumbai gets a different experience than the synthetic test predicts, and a user on a slow rural mobile connection gets a much worse one.

Real-user monitoring closes that gap. The browser's Performance Observer API can record the Core Web Vitals on every page view, with the actual user's device, network, and geography. Sent back to a small analytics endpoint, that data shows the distribution — not the average — of LCP, CLS, and INP across your real traffic. The 75th percentile of that distribution is the number Google scores you on for ranking, and the 95th percentile is the number that drives the complaints you hear from users on bad networks.

The real-user monitoring post in this topic covers a minimal implementation — about 30 lines of JavaScript and a single endpoint — that captures the metrics without sending any data to a third party. Once you have that running, the synthetic tests become useful as a CI gate (does this PR regress the lab number) while the real-user data becomes the truth source for whether actual users are getting faster or slower.

05

What to invest in first

For most teams the right first investment is measurement. Until you have real-user data on your own site, every performance change is a guess. Lighthouse will tell you a number moved; only your users can tell you whether the experience improved. Setting up RUM is a half-day of work that pays back for years.

After measurement, the highest-leverage single move on most production sites is reducing the JavaScript bundle. A bundle visualiser is the diagnostic tool: it lists every dependency by size, and the conversation about whether each one is worth its weight is usually short. Removing one over-sized icon library or replacing one heavy date utility can shave 100kb off the first load, which translates directly into LCP and INP improvements on slow networks.

After bundle size, the order depends on the site. Image-heavy sites benefit most from going through the image-optimisation deep-dive. Sites with custom fonts benefit most from the font-loading post. Heavily-interactive SPAs benefit most from the hydration deep-dive. The honest advice is to start with measurement, look at the longest item on the waterfall, and read whichever post in this topic covers it.

Web performance work has a particular discipline to it: read the trace, find the bottleneck, fix the one thing that is biggest, re-measure, repeat. Most of the posts in this topic are written around that loop. None of them are a silver bullet. All of them are small habits that, applied consistently against real measurements, produce a site that loads faster for the users who matter.

Articles in this topic

6 posts
Performance11 min read

Core Web Vitals Explained: LCP, CLS, INP Without the Buzzwords

What each Core Web Vital actually measures, where the number comes from, what user behaviour it correlates with — and the engineering moves that move each metric in production.

By Kajal PansuriyaMay 26, 2026
Performance12 min read

Auditing a JavaScript Bundle: The Largest Single Lever

How to run a real bundle audit with Webpack/Vite analyzer, the typical offenders that show up on every production site, and the replacement strategies that shave 100kb+ off first load.

By Kishan VaghaniMay 26, 2026
Performance13 min read

The Hydration Tax and How to Pay Less of It

Islands architecture, server components, and selective hydration — what each pattern actually changes about the JavaScript that ships and the timeline the user feels.

By Kishan VaghaniMay 26, 2026
Performance10 min read

A 30-Line Real-User Monitoring Setup (No Third-Party)

Performance Observer API, sending Core Web Vitals back to a small endpoint, and computing the 75th and 95th percentiles — the minimum implementation that beats Lighthouse for catching real regressions.

By Kishan VaghaniMay 26, 2026
Performance11 min read

Image Optimisation: Format, Sizing, and the Lazy-Load Rules

AVIF vs WebP vs PNG, srcset and sizes, native loading=lazy quirks, and why the LCP image should absolutely not be lazy. A working format playbook for image-heavy sites.

By Kajal PansuriyaMay 26, 2026
Performance9 min read

Font Loading Without Layout Shift

font-display strategies, the size-adjust descriptor, preloading the right weights, and the trade-off curve between flash-of-unstyled-text and cumulative layout shift.

By Kajal PansuriyaMay 26, 2026

Want a wider view?

See every topic on one page, plus the writers behind them.

All topics →