CLIEncoders
Web engineering9 min read

The technical SEO checklist for a Next.js site

Most technical SEO advice for Next.js is a list of tags. The tags are the easy part. The decisions that actually determine whether a site can rank are architectural, and three of them are painful to reverse once content exists.

1. One indexable URL per thing you want to rank for

This is the decision that outweighs everything else on this list, and the one most single-page marketing sites get wrong. A fragment — /#pcb-design — is not a URL a search engine ranks. It is a scroll position on the homepage. If you offer ten services from one page, those ten offerings are competing for the authority of a single page, and nine of them are invisible.

The fix is a real route per offering, each with its own title, description, canonical and substantive body copy. In the App Router that is a dynamic segment with generateStaticParams, prerendered at build time. It is not a large amount of code; it is a large amount of writing, which is the actual reason it gets skipped.

The corollary matters too: do not create pages you cannot fill. Ten pages of four hundred honest words each beat thirty pages of padded eighty. Thin, near-duplicate pages are actively demoted, so an empty route is worse than no route.

2. Canonical tags are inherited, and that will bite you

Next.js metadata cascades from the root layout down. Set alternates.canonical to '/' in your root layout and every page beneath it inherits that value — so each sub-page tells Google its canonical version is the homepage, which is a request to drop it from the index.

Nothing about this is visible in the browser. The pages render, the links work, and the site quietly refuses to accumulate any indexed pages beyond the homepage. It is the single most common serious SEO defect we find in App Router projects.

The fix is to override alternates.canonical on every route that sets metadata. A shared helper that takes the path and always sets the canonical from it is worth writing, because it makes forgetting harder than remembering.

3. Get the base URL right before your first crawl

metadataBase, and everything derived from it — canonicals, og:url, sitemap entries — comes from one environment variable in most setups. If that variable is set in your local .env and never added to the hosting platform, the deployed site publishes canonicals pointing at localhost.

Google's response is reasonable and total: the canonical version of each page is somewhere it cannot reach, so nothing gets indexed and shared links show a broken preview. Because .env files are gitignored by default, this failure survives code review — the repository is correct and the deployment is not.

Two defences. Resolve the base URL through a fallback chain ending at the platform's own deployment domain rather than at localhost, so a missing variable degrades to something real. And check the deployed HTML after the first deploy rather than trusting the dashboard.

4. Structured data, used for what it does

Structured data does not raise rankings. It helps a search engine understand what an entity is and makes a page eligible for richer presentation, which affects click-through — a different and still valuable thing. Being clear about that distinction saves a lot of wasted effort.

The types that earn their place for a services business are Organization for the company (with the LocalBusiness subtype where there is a real address), Service per offering with alternateName carrying query-phrase variants, BreadcrumbList because it visibly changes the snippet, and FAQPage where you have genuine questions and answers.

Two rules on FAQPage specifically, both enforced by silent failure rather than a warning. Every question and answer must appear in the page's visible HTML — which rules out accordions that fetch answers on click. And the answers must be real answers; FAQ markup used to smuggle keywords is treated as spam.

5. Core Web Vitals, in descending order of usefulness

Largest Contentful Paint is where the wins are, and the usual culprit is a hero image or webfont blocking the first meaningful paint. Serve modern formats at the right dimensions, set explicit width and height, and preload only the one image that is genuinely the LCP element.

Cumulative Layout Shift is almost always missing dimensions on images or a webfont swapping to a differently-proportioned face. Both are cheap to fix and disproportionately annoying to users.

Interaction to Next Paint is a JavaScript problem, and on a marketing site the honest fix is usually less JavaScript rather than more clever scheduling. An animation library loaded on every route to power one effect on the homepage is a common and avoidable cost.

Measure on a mid-range Android phone on a throttled connection, not on your laptop. A site that is only fast on developer hardware is not fast, and the field data Google actually uses will tell you so eventually.

What this checklist cannot do

All of the above makes a site eligible to rank and removes self-inflicted obstacles, which is genuinely most of what goes wrong. It does not make you outrank an established competitor on a competitive commercial term.

That needs content depth across many pages and links from other sites that already have authority, accumulated over months. Neither is a build task, and any agency implying otherwise is selling the easy half as though it were the whole job.