

Web Development
Published 2026-07-15 · Updated 2026-07-23 · 9 min read
Sapun Lamichhane
Founder & CEO of Arcetis
Most Core Web Vitals advice focuses on optimization techniques — compress images, defer scripts, minimize third-party tags — applied after a site's architecture is already decided. That advice isn't wrong, but it's secondary. The single decision that most determines a Next.js site's Core Web Vitals ceiling is made earlier: which rendering strategy is used for a given page, before any individual optimization technique gets applied on top of it.
Next.js supports several rendering strategies for the same page — static generation at build time, server-side rendering per request, and client-side rendering after an initial shell loads — and each has a fundamentally different relationship to Largest Contentful Paint, Cumulative Layout Shift, and Interaction to Next Paint, the three metrics Core Web Vitals actually measures.
“A static or server-rendered page has no per-request database query or application logic running between a visitor's click and the page appearing. A dynamic site has to do real work on every single request, no matter how well-optimized that work is.”
A statically generated page's HTML is produced once, at build time, and served as-is from a CDN — there's no database query, no server-side rendering computation, and no application logic running per request between a visitor's click and the page appearing. Largest Contentful Paint improves because there's no server-side computation delay between the request and the first byte of real content arriving; the content is already sitting there, ready to serve.
A page that instead fetches its content client-side after an initial near-empty shell loads has to wait for that shell to load, then request data, then render it — each step adding time before the largest content element actually paints. This is the most common, avoidable cause of a poor LCP score in a Next.js app: content that could have been known at build time being fetched client-side instead, out of habit rather than necessity.
Cumulative Layout Shift is easier to keep low when content dimensions are known and stable at build time, rather than streaming in after a client-side data fetch shifts the layout around it. A static or server-rendered page can reserve the correct space for an image or embed before it loads, because the final layout is already determined when the HTML is generated.
A common CLS failure mode in Next.js apps isn't a missing width/height attribute — modern Next.js `<Image>` components largely prevent that specific mistake by default. It's dynamically-loaded content (a personalization banner, an A/B test variant, a client-fetched widget) inserting itself into the layout after the initial paint, pushing everything below it down. That's an architecture decision about what loads when, not a CSS property that got forgotten.
Interaction to Next Paint measures how long a page takes to visibly respond after a user interacts with it — a click, a tap, a keypress. A page can look fully loaded and still feel sluggish if a heavy script is blocking the main thread when a user tries to interact with it, regardless of how fast the page appeared to load in the first place.
A site with no server-side application code running on a visitor's request — no API routes, no server actions competing for the main thread during interaction — has more of the main thread free to respond to input when it matters. This is an indirect but real benefit of a leaner rendering architecture: fewer moving parts competing for the same thread means a faster response when a visitor actually does something.
None of this makes static generation universally correct, and the honest framing matters. Content that genuinely needs to change per request or per visitor — real-time inventory counts, a logged-in dashboard showing personal data, prices that vary by account tier, live availability — can't be pre-rendered at build time, because the content by definition isn't the same for every visitor, or doesn't exist yet when the build runs.
The actual decision is per-page, sometimes per-section, not a permanent identity for a whole site: a marketing page, a blog, a service page — all static-shaped, because nothing on them is personalized per visitor. A logged-in account dashboard or a live checkout flow — not static-shaped, no matter how much of the rest of the site is, and forcing it to be static doesn't make it faster, it makes it wrong.
Partially — SSR still avoids client-side data-fetch delay since content renders on the server before reaching the browser, but it reintroduces a per-request server computation step that static generation eliminates entirely, so static generally has a lower LCP ceiling when the content genuinely allows it.
Yes, and it's the normal pattern — marketing pages statically generated, a logged-in dashboard server-rendered or client-rendered, within the same Next.js app. The decision is made per route based on whether that route's content is the same for every visitor.
No — Lighthouse runs a single simulated lab test; Core Web Vitals as Google actually uses them for ranking come from real-user field data (the Chrome User Experience Report). A site can score well in a lab test and still show a worse field score under real network conditions and real device performance.