Next.js gives you everything you need to rank, but the defaults are not enough and the surface area is wide. This is the short list of what actually moves the needle in 2026, with the App Router specifics — not generic SEO advice you have read a hundred times.
1. Treat the Metadata API as the source of truth
Every route should export metadata (or generateMetadata for dynamic routes). Set metadataBase once in the root layout so relative OG image URLs resolve, and set a per-page alternates.canonical so query-string and trailing-slash variants collapse to one indexable URL.
export const metadata: Metadata = {
metadataBase: new URL("https://example.com"),
title: "Page title with the primary keyword up front",
description: "150–160 chars, primary keyword + the benefit.",
alternates: { canonical: "/the-page" },
openGraph: { type: "article", images: ["/opengraph-image.png"] },
};Keep titles under ~60 characters and descriptions near 155 so they do not truncate in the SERP. Google rewrites descriptions often, so spend the effort on titles first.
2. Ship JSON-LD, and connect the nodes with @id
Structured data is how you become an entity instead of a page. A personal or product site wants a Person or Organization node and a WebSite node, plus page-type schema (TechArticle, SoftwareApplication, BreadcrumbList). The detail most people miss: give nodes a stable @id and reference them across pages so the graph is one connected entity, not isolated blobs.
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify({
"@context": "https://schema.org",
"@type": "TechArticle",
"@id": "https://example.com/writing/slug#article",
"headline": "…",
"author": { "@id": "https://example.com/#person" },
}),
}}
/>3. Add llms.txt for AI crawlers
A growing share of discovery now runs through ChatGPT, Perplexity, and Claude, and they reward a clean, plain-text summary of your site. Serve /llms.txt (a concise map) and optionally /llms-full.txt (the long version). Keep the facts in these files identical to what your pages and JSON-LD say — contradictory numbers across your own surfaces erode citation confidence. This is its own discipline; I treat it as part of AI-search optimization, and the AHTML project automates emitting it.
4. Make robots.txt explicit about AI bots
Decide deliberately whether GPTBot, ClaudeBot, PerplexityBot, Google-Extended and friends may crawl, and say so by name in app/robots.ts. Defaulting to silence means the answer is decided by someone else's defaults.
5. Keep sitemap lastmod honest
The biggest self-inflicted wound I see: generating lastModified: new Date() in app/sitemap.ts on every build. That tells Google every page changed on every deploy, so it learns to distrust the signal and crawls you less. Use stable, per-page dates and only bump one when that page's content actually changes.
6. Optimize for INP, not FID
Core Web Vitals in 2026 means INP (Interaction to Next Paint), LCP, and CLS — FID is gone. Next.js helps with LCP via the next/image component and font optimization, but INP is about your own JavaScript: break up long tasks, defer non-critical hydration, and keep the main thread free on interaction. Measure field data in Search Console's Core Web Vitals report, not just lab Lighthouse.
7. Render content server-side, then verify it
With the App Router this is mostly free — Server Components render HTML crawlers can read without executing your JS. Verify it: fetch your page with JavaScript disabled and confirm the headings and copy are present. If your content only appears after hydration, you are betting on the crawler running your bundle.
The short version
Metadata API on every route, a connected JSON-LD entity graph, llms.txt that agrees with your pages, an explicit robots.txt, an honest sitemap, INP discipline, and server-rendered content you actually verified. This site is built on exactly these rules — see the Next.js SEO hub for the deeper dive, or the projects for where it is applied.