Losing clicks to competitors? Find out exactly why, and what to fix first.

Show me why
Skip to content

Web Design

Next.js SEO: Rendering, Metadata and Sitemaps

Add saadrazaseo.com as a preferred source on Google

Free and no obligation. A real reply from me, not a bot.

Next.js SEO works when important pages are rendered on the server or at build time, each route sets its own title, description and canonical through the Metadata API, and the app generates a sitemap and robots file. Client-only rendering can work for Google, but it adds delay and risk you rarely need to take.

The HTTP Archive’s 2024 Web Almanac found canonical tags on 65 per cent of mobile pages and 69 per cent of desktop pages, which shows how routinely this one tag is relied on and how easily it is mishandled in a framework.

Why a framework changes the SEO job

On a hosted builder, the platform decides the HTML. In Next.js, you do. That is liberating for a developer and hazardous for a marketer, because nothing prompts you to write a title or output a link a crawler can follow. If it is not in the code, it is not on the page.

When I audit a Next.js site, I start with one question: what does the server return before any JavaScript runs? If the answer is a near-empty shell with a spinner, the rest of the SEO work is built on sand. If the answer is complete HTML with a title, a heading, content and links, you are in a good position, and the remaining tasks are the same ones every site has.

I write this guide with the App Router in mind, as that is the current way to build Next.js apps, and mention the older Pages Router where it differs. Framework features are renamed and reorganised from time to time, so check the nextjs.org documentation for the current API before copying anything. If the decision of whether to use a framework at all is still open, my best CMS for SEO comparison covers the alternatives, and the post on headless CMS SEO covers the common pairing of Next.js with a separate content system.

Rendering options and what they mean for crawling

Google’s documentation on JavaScript SEO basics describes three phases: crawling, rendering and indexing. Pages with a 200 status go into a render queue where a headless Chromium runs the JavaScript, and Google then indexes the rendered content. It also says server-side rendering remains beneficial for speed and crawler compatibility. So Google can handle client-side rendering, but you add a step and a dependency, and other crawlers and tools may not manage it as well.

ApproachHow it worksGood forWatch out for
Static generation (SSG)HTML built at deploy timeMarketing pages, docs, blog postsStale content until the next build, unless you revalidate
Incremental regenerationStatic pages refreshed on a schedule or on demandLarge catalogues and content that changes occasionallyMisconfigured revalidation can show old prices or stock
Server-side rendering (SSR)HTML built per requestPersonalised or constantly changing pagesSlower responses if data fetching is slow
Client-side rendering (CSR)Browser builds the page from JavaScriptLogged-in dashboards, toolsContent missing from initial HTML, extra delay before indexing

My decision rule is simple. Anything you want to rank is static or server-rendered. Anything behind a login can be client-rendered. The in-between cases, such as a product page with live stock, can usually be a static or server-rendered page with a small client component for the live part.

Two practical checks follow from Google’s guidance. First, use real a elements with href attributes for navigation, not click handlers on other elements, because Google parses links from href attributes. Second, return proper status codes: a missing page should respond with a 404, not a 200 with a “not found” message, which Google describes as a soft 404.

Your competitors are in the map pack. Are you?

See what is keeping you out of the local results.

Check my Maps visibility

Metadata: titles, descriptions and canonicals

The App Router provides a Metadata API. You export a static metadata object from a page or layout, or an async generateMetadata function when values depend on data, such as a product name. The same mechanism covers the title, description, canonical URL, Open Graph and robots settings.

The pattern I recommend:

  1. Define defaults in the root layout, including a title template that adds the brand name.
  2. Override per route with a specific title and description, never the defaults.
  3. For dynamic routes, use generateMetadata to fetch the item and build its title and description from real data.
  4. Set the canonical for every indexable page through the alternates option, using an absolute URL.
  5. Set the robots option to noindex on pages that should stay out of results, such as internal search or thank-you pages.

The most common mistakes are shared. A site-wide canonical defined in the root layout is inherited by every page, so all pages claim to be the homepage. Titles copied from a layout appear identical on thousands of routes. Test by viewing the rendered source of several different page types, not just the homepage.

Canonical tags are a hint to Google, not a command, and they work best when your internal links, sitemap and redirects agree with them. On a framework, those four are written by four different pieces of code, so check they point at the same URL, including trailing slash and host name rules.

Sitemaps and robots.txt

The App Router supports special files for both: a sitemap file and a robots file, written as code that returns the entries. For a site with dynamic routes, generate the sitemap from the same data source that builds the pages, so the two cannot drift apart. List only canonical, indexable, 200 status URLs.

For robots.txt, keep the rules minimal. Block genuinely useless areas, such as internal search results or API routes, and point to the sitemap. Remember that robots.txt controls crawling, not indexing, so it is not the way to keep a page out of results; use a noindex instruction for that. The most damaging mistake in this area is a staging rule that blocks everything and is promoted to production, so check the live file after every launch, as in my website launch SEO checklist.

Internationalisation

If the site serves several languages or regions, each version needs its own URL, translated metadata and annotations that link versions together. Google’s guidance on localised page versions says hreflang can be placed in HTML tags, HTTP headers or the sitemap, that there is no benefit in using all three, and that annotations must be reciprocal with each page referencing itself.

The Pages Router offered built-in internationalised routing configuration. In the App Router, the usual approach is a locale segment in the path and your own logic to build the annotations. Whichever method you use, the metadata alternates option and the sitemap are the natural places to output the hreflang set. Test it by checking that every language page lists every other version and itself. Do not auto-redirect visitors by browser language without leaving each version reachable by a plain URL, because crawlers do not behave like a visitor in your country.

Images, fonts and Core Web Vitals

Next.js ships components for images and fonts that handle sizing, lazy loading and font loading. They help, but they do not fix a poor page. A hero image that is the largest element on the screen should be loaded with priority and sized correctly, and below-the-fold images should load lazily.

The targets, defined on web.dev, are Largest Contentful Paint within 2.5 seconds, Interaction to Next Paint of 200 milliseconds or less and Cumulative Layout Shift of 0.1 or less, at the 75th percentile of page loads. In a JavaScript-heavy app, the usual culprits are:

  • Large client bundles that delay interaction. Keep components on the server unless they need browser features.
  • Third-party scripts for analytics, chat and tag managers loaded on every page.
  • Images and embeds without reserved dimensions, which cause layout shifts.
  • Late-loading fonts that change the layout when they arrive.

Measure with real-user data where you have it, and use lab tools to find the cause. A good score on your developer’s fast laptop says little about a mid-range phone on a slow connection.

How I would approach a Next.js build

This work belongs in the design and development phase, before launch. It is far cheaper to decide on rendering, URLs and metadata at the start than to retrofit them, which is why I treat it as part of SEO web design and development. A short sequence works well:

  1. Decide the rendering mode for each type of route and write it down.
  2. Define the URL scheme and the redirect rules in configuration. Permanent redirects should use a status Google recognises, which means 301 or 308.
  3. Build the metadata defaults, then override per route type.
  4. Generate the sitemap and robots files from live data.
  5. Check rendered HTML, canonicals and status codes in a staging build.
  6. Test performance on mobile and fix the largest bundles first.
  7. Launch, then watch Search Console for crawl and indexing issues for several weeks.

If the same team also runs a marketing site on a visual builder, the trade-offs differ. The Webflow SEO guide and the Framer SEO guide describe what you gain and give up there, and the BigCommerce SEO store checklist covers the commerce case.

Questions people ask about Next.js SEO

Is Next.js good for SEO?

Yes, when pages are statically generated or server-rendered and each route sets proper metadata. It is not automatic, because the framework lets you ship a page without a title or with the wrong canonical.

Does Google index client-side rendered pages?

Google can render JavaScript and index the result, but it processes pages in stages, and its own documentation says server-side rendering remains beneficial for speed and crawler compatibility. For pages you want to rank, avoid depending on client rendering.

How do I set a canonical URL in Next.js?

Use the Metadata API’s alternates option on each page or in generateMetadata, with an absolute URL. Avoid defining one canonical in the root layout, as every page would inherit it.

How do I generate a sitemap in Next.js?

With the App Router, add a sitemap file that returns your URLs as code, and build it from the same data that generates your pages. Include only canonical, indexable pages.

If you are planning a Next.js build or inheriting one that is not getting indexed, I can review rendering, metadata and crawl behaviour with your developers. Ask for a free audit through the contact page.

More in this series (SEO by website platform): start with Best CMS for SEO: WordPress vs Shopify vs Webflow vs Custom, then explore:

Want more calls from Google Maps?

Tell me about your business and area, and I will review your local search visibility.

Your details are only used to reply to your request. No spam.

Grow my trafficCall