Next.js gives you server rendering, static generation and a metadata API out of the box, which removes the classic SEO problems of single-page apps. It does not configure SEO for you. Duplicate URLs, missing hreflang, sitemaps with fake dates and structured data that contradicts the page are still common on Next.js sites we audit. This guide is the setup we use on multilingual App Router projects, aligned with what Google's documentation says it actually uses — and what it ignores.
Start with what Google says matters
Technical SEO makes good content discoverable; it does not replace it. Google's guidance centers on helpful, reliable, people-first content (Google: creating helpful content). Its spam policies explicitly target scaled content abuse — generating many pages, with AI or otherwise, primarily to manipulate rankings rather than help users (Google: spam policies). Using AI to help write content is fine; publishing unhelpful content at scale is not (Google: AI-generated content guidance).
Everything below assumes the pages are worth indexing.
1. Render content on the server
Google can render JavaScript, but rendering is deferred and resource-limited (Google: JavaScript SEO basics). With the App Router, keep indexable content — headings, body text, links — in Server Components so it is in the initial HTML. Use real <a href> links for navigation (next/link renders them); links that exist only as click handlers are not crawlable (Google: crawlable links).
2. Titles, descriptions and canonical URLs
Use the Metadata API: a static metadata export for fixed pages, generateMetadata for dynamic ones (Next.js: generateMetadata).
// app/blog/[slug]/page.tsx
export async function generateMetadata({ params }: PageProps<"/blog/[slug]">): Promise<Metadata> {
const { slug } = await params
const post = getPost(slug)
if (!post) return {}
const url = `https://example.com/blog/${slug}`
return {
title: post.title, // unique, descriptive, ~50–60 characters
description: post.description, // a real summary, ~140–160 characters
alternates: {
canonical: url,
languages: {
"en-US": url,
"uk-UA": `https://example.com/ua/blog/${slug}`,
"x-default": url,
},
},
openGraph: {
type: "article", url, title: post.title, description: post.description,
publishedTime: post.date, modifiedTime: post.updated ?? post.date,
},
}
}
Guidelines from Google's documentation:
- Titles should be unique and descriptive; Google may rewrite titles that are vague, stuffed with keywords or identical across pages (Google: title links).
- Meta descriptions are not a ranking factor but often become the snippet; write a specific summary for each page (Google: snippets).
- Canonical URLs tell Google which of several duplicate URLs to index — trailing slashes, query parameters, tracking codes (Google: consolidate duplicate URLs).
3. hreflang for multilingual sites
If you publish the same article in several languages, tell Google which versions belong together. Each language version must list all versions including itself, the annotations must be reciprocal, and an x-default should point to the fallback (Google: localized versions). Next.js renders alternates.languages as <link rel="alternate" hreflang="..."> tags.
Two common bugs:
- Listing a translation that does not exist. Generate alternates from the content you actually have, not from a list of supported locales.
- Pointing canonical to another language. Each language version is canonical to itself; hreflang connects them.
4. Sitemaps with honest dates
Generate the sitemap from your content with app/sitemap.ts (Next.js: sitemap). What Google uses:
- Google ignores
priorityandchangefreq. - Google uses
lastmodif it is consistently and verifiably accurate, meaning the date of the last significant change to the main content, structured data or links (Google: build a sitemap).
So don't set every page's lastModified to the build time. Store an updated date for each article and use it:
// app/sitemap.ts
export default function sitemap(): MetadataRoute.Sitemap {
return getAllPosts().map((post) => ({
url: `https://example.com/blog/${post.slug}`,
lastModified: new Date(post.updated || post.date), // real content changes only
alternates: { languages: hreflangFor(post.slug) },
}))
}
Pair it with app/robots.ts that references the sitemap and does not block CSS or JavaScript (Next.js: robots).
5. Structured data that matches the page
JSON-LD helps Google understand the page; in Next.js, render it in a <script type="application/ld+json"> tag from the page component (Next.js: JSON-LD). For articles, Google recommends headline, image, datePublished, dateModified and author with a name and ideally a URL (Google: Article structured data).
const jsonLd = {
"@context": "https://schema.org",
"@type": "BlogPosting",
headline: post.title,
description: post.description,
inLanguage: "en-US",
datePublished: post.date,
dateModified: post.updated ?? post.date,
author: { "@type": "Person", name: post.author },
image: [`https://example.com/og/${post.slug}.png`],
mainEntityOfPage: `https://example.com/blog/${post.slug}`,
}
Things to know in 2026:
- FAQ rich results are shown only for well-known, authoritative government and health websites, and HowTo rich results were deprecated in 2023 (Google: changes to HowTo and FAQ rich results). FAQ sections are still useful content for readers; just don't expect FAQ markup to change how your page looks in results.
- Dates must be visible and consistent. Show the publication date and, when relevant, the updated date on the page itself, and make the structured data match (Google: publication dates).
- Breadcrumbs via
BreadcrumbListhelp Google understand site hierarchy.
6. Internal linking
Internal links are how crawlers discover pages and how Google understands which pages are related and important. For a blog:
- Link from each article to two to five genuinely related articles, in context, with descriptive anchor text — not "click here".
- Show a related-articles block chosen by topic, not just the latest posts.
- Give headings stable
idattributes so other pages can link to specific sections. - Keep important pages within a few clicks of the homepage, and avoid orphan pages that nothing links to.
7. Performance and accessibility
Page experience matters too. Core Web Vitals are used by Google's ranking systems; we cover INP, LCP and CLS fixes in Core Web Vitals in 2026. Accessible markup — semantic headings, alt text, labelled forms — helps users and machines read your pages, and in the EU it is increasingly a legal requirement, see Web accessibility in 2026.
Technical SEO checklist for Next.js
- Indexable content rendered on the server; navigation uses real links
- Unique title and description for every page
- Self-referencing canonical URL on every page
- hreflang generated only for existing translations, reciprocal, with
x-default - Sitemap from content with accurate
lastModified; no fake build dates - robots.txt references the sitemap and does not block assets
- JSON-LD for articles and breadcrumbs, consistent with visible content
- Visible published and updated dates
- Topic-based related articles and contextual internal links
- Core Web Vitals monitored with field data
- Search Console verified, sitemap submitted, coverage reviewed monthly
Upgrading to Next.js 16 changes a few APIs relevant here, such as async params in metadata functions; see Next.js 16 in production.
FAQ
Do I need a separate SEO library with the App Router?
No. The built-in Metadata API, sitemap.ts and robots.ts cover what most sites need.
Should every blog post have FAQ schema? It will not produce FAQ rich results for most sites. Keep FAQ content if it helps readers; the markup is optional.
How often should the sitemap update? Whenever content changes significantly. Generating it from content at build or request time keeps it accurate automatically.
Does AI-written content hurt SEO? Google evaluates helpfulness, not authorship. Content that is accurate, original and useful is fine; mass-produced pages without value violate spam policies.
Sources
- Google Search Central. Creating helpful, reliable, people-first content and Spam policies.
- Google Search Central. Build and submit a sitemap.
- Google Search Central. Tell Google about localized versions of your page.
- Google Search Central. Article structured data and Changes to HowTo and FAQ rich results.
- Google Search Central. JavaScript SEO basics, Consolidate duplicate URLs.
- Next.js. generateMetadata, sitemap, robots, JSON-LD.