Every one of these came out of a real audit, and every one of them was shipped by someone who had read the docs.
None of the four need a rewrite and none of them show up as an error. They're what I look for first when someone hands me a codebase and asks why it feels slow, and they turn up often enough that they're most of what fills Next.js notes.
Client boundary too high
Someone needs a useState for a dropdown, so use client goes at the top of the page. Everything below it — the whole page, its cards, its formatting helpers, the date library it imported — now ships to the browser as JavaScript.
The boundary belongs at the leaf, not the root. Keep the page a server component and make the dropdown its own client component. The rest of the tree stays server-rendered and ships nothing.
At the root
The whole page ships as JavaScript
At the leaf
Only the dropdown ships
Fetching in layouts
Layouts don't re-render on navigation between the routes they wrap. That's usually what you want, but it means data fetched in a layout can be stale in a way that's genuinely hard to debug — the page shows fresh content next to a header that hasn't moved.
Fetch in the page. If two pages need the same data, fetch it in both and let the request be deduplicated, rather than hoisting it into a layout to feel efficient.
In the layout
Stale after the first navigation
In the page
Fresh on every navigation
Hand-written metadata
Titles typed twice, canonical URLs missing on half the routes, an OpenGraph description that no longer matches the page. This is what happens when metadata is written per route by hand instead of derived from the same object that renders the page.
What to derive instead of type
- 01
Title and description
From the same content object that renders the page. Typed twice is already a bug.
- 02
Canonical path
From the route params. Missing on half the routes is the usual failure.
- 03
OG image
From the file convention rather than a static asset sitting in a folder nobody updates.
- 04
Sitemap and JSON-LD
From the same source as the page. If adding a route means editing more than one file, that's the bug.
If adding a page means editing more than one file, that's the bug.
It's the same principle as how I scope a project — decide once, write it down once, derive everything else from it.
Images without dimensions
next/image without width and height — or fillwith a sized parent — gives you layout shift, and layout shift is the easiest Core Web Vitals score to lose by accident. It's also the easiest to fix, because the compiler will tell you where every one of them is.
Wrap it. One component that requires dimensions and sets a sensible sizes means the mistake becomes impossible rather than merely discouraged. You can see the pattern across the builds in my portfolio, and the details are in the Next.js docs.
Without dimensions
The page jumps as images load
Wrapped once
The mistake becomes impossible
What these four cost a business
None of this is about elegance. A client boundary in the wrong place means a phone on a train takes three extra seconds to show anything, and three seconds is where people leave. Data fetched in a layout means someone on your team eventually opens a support ticket about a number that looks wrong, spends a day chasing it, and finds nothing — because the number is only stale on the second page a visitor lands on, which is the one nobody thinks to test.
Hand-written metadata is the expensive one, because it fails quietly. Nobody notices a missing canonical tag the week it ships. You notice it six months later as a flat line in a traffic graph, and by then the fix is still an hour of work but the six months are gone. Images without dimensions are the same shape of problem: the page looks fine, so nobody reports it, and the score costs you rankings in the background.
01
Three extra seconds
A client boundary in the wrong place. A phone on a train. That's where people leave.
02
A stale number
A support ticket, a day chasing it, nothing to find — it's only wrong on the second page.
03
A missing canonical
Nobody notices the week it ships. You notice six months later as a flat line in traffic.
04
Layout shift
The page looks fine, so nobody reports it. The score costs you rankings in the background.
That's the whole reason these four are worth writing down. They are afternoon fixes with month-long payoffs, they don't need a migration, and they don't need anyone's permission to start. If you're deciding whether an existing codebase needs a rebuild or a repair, this is where I look first — and most of the time the honest answer is repair, which is a fraction of the budget.
If that sounds like your app, the fastest version of this is an hour on a call with the repo open. Most of the work I take on starts there rather than with a proposal.

