Technical SEO
Technical SEO for Next.js
Crawlability, canonicals, hreflang and structured data built into the render path - generated from one source of truth instead of maintained by hand.
Technical SEO in a Next.js application is not a plugin. It is a property of how the application renders, and it fails in ways that are invisible from the browser: a canonical tag that points at the wrong locale, an hreflang cluster that advertises translations that do not exist, a sitemap generated from a different list of routes than the router actually serves.
None of that shows up in a page that looks correct when you open it. It shows up months later as two URLs splitting one page's rankings, or a locale that was never indexed at all.
What we audit
- Crawl and render. What the crawler receives in the initial HTML versus what appears after hydration, and which of your content only exists in the second one.
- Canonicalisation. Trailing slashes, query parameter handling, pagination, and whether every route agrees with itself about its own address.
- International routing. The full hreflang cluster, including
x-default, validated against the translations that actually exist rather than the ones that were planned. - Structured data. A connected
@graphwith stable@idreferences, not four disconnected blobs that each re-declare the organisation. - Sitemaps and robots. Generated from the same route source the application renders from, so the two cannot drift.
The five faults we find most often
A canonical that was never written. generateMetadata is optional, so a
route without one inherits nothing and Google chooses an address for you -
often the one with a tracking parameter attached.
Two URLs that both answer. /about and /about/, or a locale served at
both /en/about and /about. Both return 200, both get indexed, and the
page's authority is divided between them. The fix is a redirect, not a
canonical, and the difference matters.
hreflang that advertises a translation nobody wrote. A locale list in a config file generates the alternates, so every page claims four languages while only two exist. Google follows the tag, finds the wrong language or a 404, and discounts the cluster. The rules, in detail.
A sitemap built from a second list of routes. Maintained by hand, or generated from a directory scan that does not know about route groups. It drifts within one sprint and then quietly misreports every date.
Structured data that describes nothing. Four separate JSON-LD blocks, each declaring its own Organization, none of them referring to each other. Valid JSON, no graph, and nothing for a search engine to resolve into an entity. What a connected graph looks like.
How we fix it
By making it impossible to get wrong. Canonicals, alternates and structured data get generated from a single typed helper that every route must call. A page cannot ship without a canonical, because the metadata function will not compile without one.
That is the whole method, and it is worth stating plainly because it is the opposite of how most technical SEO is delivered. A findings document that lists forty issues gets forty fixes, and then the forty-first page ships without a canonical because the list was a snapshot and nobody re-ran it. A generated canonical cannot be omitted on the next page, because there is no code path that produces a page without one.
The same applies to the sitemap and the feed: both are derived from the route source the application renders from, so a new page appears in them because it exists, not because somebody remembered. And hreflang is generated from the translations present on disk, so deleting a translation removes its tag on the next build rather than leaving a claim behind.
Where generation is not possible, the check moves into CI instead. This site fetches every URL in its own sitemap on every push and fails the build on a missing, duplicated or mismatched canonical, on a page absent from its own hreflang cluster, and on a duplicate URL form that answers instead of redirecting. The reasoning behind that check.
This site is built that way, and the implementation is public - the
buildMetadata helper and the JSON-LD graph in this repository are the same
pattern we deploy for clients.
Multilingual, which is where it usually breaks
A single-language site has one way to get canonicalisation wrong. A
four-language site has the locale prefix, the default locale served without
one, the x-default target, the translation that exists in two languages but
is claimed in four, and a language switcher built from a <select> that a
crawler cannot follow to any of them.
We treat the locale list, the prefix rule and the translation inventory as one source that metadata, the sitemap and the switcher all read from. The architecture that produces is the difference between a site with four locales and a site with one locale and three orphans.
What we do not do
Not content strategy, not keyword research, not link acquisition. This is the engineering floor those things stand on, and a team that sells you all four at once is usually strong at one of them.
We will tell you when the technical work is not your constraint. If your pages are indexed correctly, resolve cleanly and validate, and the traffic still is not there, the answer is in the content and we will say so rather than invoicing for a second audit.
How an engagement runs
A fixed read first - crawl, render comparison, canonical and hreflang validation across every route template, structured data validation, and log analysis where server logs are available. That produces a findings document ranked by impact with each item traced to the code that causes it.
Then the fixes, as pull requests in your repository, in that order. Then the checks that keep them: generation where the fault was a missing value, CI assertions where generation is not possible.
If you only want the first part, the findings document stands on its own and several clients have implemented it themselves. That is a reasonable outcome and the audit is the engagement for it.
The measurable outcome
Correct indexation of the routes you want indexed, and nothing else. Rich results where the schema supports them. An hreflang cluster that Search Console validates without warnings. These are not growth hacks; they are the floor a content strategy stands on.
What you receive
The findings ordered by what they cost you, the fixes as pull requests, and the checks that stop them returning. Canonical and sitemap derived from one source, hreflang read from the files instead of a list, and a crawl in CI that fails on a linked 404.
Plus the before and after: pages indexed, the ones Search Console was refusing and the reason it gave, and what changed once the fix had time to be recrawled. That last number arrives weeks after the work and we send it anyway.
