S
Back to all articles
Performance

5 Decisions That Make a Next.js Site Feel Instant (Not Just Score Well)

A 100/100 Lighthouse score and a site that *feels* fast are not the same thing. These are the five architectural calls that actually move the needle on perceived speed.

Published · May 3, 20267 min read
#Next.js#Performance#React#Web Vitals

Clients ask for "a fast site" the way they ask for "a modern design" — it is a feeling, not a metric. You can chase a perfect Lighthouse score and still ship something that feels sluggish the moment a real user taps a filter or opens a menu. Perceived speed is a different discipline than lab-measured speed, and it is won or lost in a handful of architectural decisions made early.

1. Server Components by default, client components by exception

The biggest win in the App Router is shipping less JavaScript, not optimizing the JavaScript you already have. I treat "use client" as a deliberate decision that needs a reason — interactivity, browser APIs, or state — not a default copy-pasted at the top of every file.

2. Treat fonts and images as layout-critical, not decorative

next/font and next/image solve 80% of layout-shift complaints by reserving space and serving the right format at the right size. The remaining 20% is discipline: explicit width/height, sane "sizes" attributes, and never letting a hero image be the largest contentful element without a priority hint.

3. Animate transform & opacity — nothing else, ever

TakeawayAnimating "top", "width", or "box-shadow" forces the browser to re-layout and re-paint on every frame. Transform and opacity run on the compositor thread — they are nearly free. Every animation in a production interface should be auditable against this one rule.

4. Stream what is slow, render what is fast

Suspense boundaries let a page paint its shell and primary content immediately while a slower data dependency — a recommendation feed, an analytics widget — streams in afterward. The user is reading and scrolling before the "complete" page would have even responded.

5. Pre-decide your loading and error states — do not improvise them

  • Skeletons should mirror the real layout dimensions — not generic gray boxes — so nothing jumps when content arrives.
  • Every async action needs a designed "in-flight" state: disabled controls, spinners with purpose, optimistic UI where it is safe.
  • Error boundaries should feel like part of the brand, not a stack trace that escaped to production.

None of these five decisions show up as a single Lighthouse number. They show up in the half-second where a user decides, subconsciously, whether your product respects their time. That half-second is the whole game.

Share this articleWhatsAppX / Twitter

Have a project that needs this kind of thinking?

Start a conversation