Quick Takeaway
Technical SEO for a Next.js site means making sure every important page returns its full content in server-rendered HTML, has a unique title, description and canonical URL, is listed in a sitemap, returns the right status code, passes Core Web Vitals, and carries valid structured data. Then you verify each of these with real tools, not assumptions.
Key takeaways
- Put content in the initial HTML. Do not make crawlers execute JavaScript to see your main text.
- Use the Metadata API for titles, descriptions, canonicals and social tags, so they are generated on the server.
- Give every page one canonical URL, and keep trailing slashes, redirects and sitemap entries consistent with it.
- Treat Core Web Vitals as field data from real users, not just a Lighthouse score.
- Test with Search Console, the Rich Results Test and a plain "view source" check.
Next.js gives you the tools to build a fast, search-friendly site, but it will not do the SEO for you. Plenty of well-built Next.js sites lose traffic to avoidable problems: content that only appears after JavaScript runs, duplicate URLs, missing canonicals, or pages that return the wrong status code.
This checklist covers what to verify, how the relevant Next.js feature helps, and how to test it. It is the same foundation we build into client sites through our SEO and web development services, and it underpins the AI search optimization work that sits on top.
Next.js features and the SEO job they do
| SEO task | Next.js feature | What to check |
|---|---|---|
| Titles, descriptions, social tags | metadata export or generateMetadata | Unique per page, rendered in the server HTML |
| Canonical URL | alternates.canonical in metadata | Absolute HTTPS URL, matches your preferred form |
| XML sitemap | app/sitemap.ts | Only canonical, indexable, 200-status URLs |
| Crawl rules | app/robots.ts | Nothing important blocked; sitemap declared |
| Correct status codes | notFound() and a not-found page | Missing pages return 404, not 200 |
| Social preview images | opengraph-image files or metadata images | Every shareable page has one |
| Fonts | next/font | Self-hosted, no layout shift on load |
| Images | next/image | Sized, lazy-loaded below the fold, priority for the LCP image |
1. Make sure content is in the initial HTML
Googlebot can render JavaScript, but rendering is a second, slower step and it can fail on heavy or broken scripts. Many other crawlers, including a number of AI crawlers, may not run JavaScript at all. The safe approach is to have your headings, body text, links and structured data in the HTML the server sends. In Next.js that means server components, static generation or server-side rendering for anything you want indexed, with client components reserved for interactivity.
The 10-second test
Fetch your page with a plain HTTP request, or use "view source" in the browser (not the inspector). If your headline and main paragraphs are in that raw HTML, crawlers can read them. If the body is an empty container, they may not.
2. Titles, descriptions and canonicals
Use the Metadata API so these are generated on the server. Each indexable page needs its own title and meta description, an absolute canonical URL, and one clear H1.
export const metadata = {
title: 'Technical SEO Checklist for Next.js',
description: 'What to verify, and how to test it.',
alternates: { canonical: 'https://www.example.com/blog/technical-seo/' },
}Set a metadataBase in your root layout so relative URLs resolve correctly, and use generateMetadata for dynamic routes such as blog posts.
3. One URL per page
- Pick one hostname (with or without www) and redirect the other to it.
- Pick a trailing-slash convention and enforce it. Next.js has a trailingSlash setting, and your canonicals, sitemap and internal links should all match.
- Strip or canonicalise tracking parameters so the same page is not indexed under many URLs.
- Redirect old URLs with a permanent redirect rather than deleting them.
Static exports need host-level redirects
If you build with output "export", Next.js config redirects and headers do not run, because there is no server. Set redirects and security headers at your host or CDN instead, for example in a vercel.json file or your web server configuration.
4. Sitemap and robots
Generate the sitemap from the same data as your pages, so a new page cannot be forgotten. List only URLs that are canonical, indexable and return 200. Declare the sitemap in robots.txt, and check that robots.txt is not accidentally blocking CSS, JavaScript or important sections. If you want to decide how AI crawlers may use your content, see our guide to robots.txt and llms.txt for AI crawlers.
5. Structured data
Add JSON-LD in a server component so it is present in the HTML. Use types that match the page: Organization and WebSite site-wide, Article or BlogPosting for posts, BreadcrumbList for navigation, and Service for service pages. Only mark up what is visibly on the page, and validate it before release.
Be realistic about rich results
Google now limits FAQ rich results to well-known government and health sites, so FAQ markup will not usually produce a special result for a business site. Question-and-answer sections are still valuable for readers and for answer engines, and valid markup helps machines understand the page.
6. Core Web Vitals
| Metric | Measures | Good threshold |
|---|---|---|
| LCP (Largest Contentful Paint) | How fast the main content appears | 2.5 seconds or less |
| INP (Interaction to Next Paint) | How quickly the page responds to input | 200 milliseconds or less |
| CLS (Cumulative Layout Shift) | How much the layout jumps around | 0.1 or less |
These are judged on real-user field data, at the 75th percentile, so a perfect Lighthouse run does not guarantee a pass. Common Next.js wins are: keep the LCP element out of client-only animation, use next/font, size images, defer heavy components with dynamic imports, and avoid shipping large libraries to pages that do not need them.
7. Status codes and error pages
A page that does not exist should return a real 404, not a 200 with a friendly message (a "soft 404"). Use notFound() in dynamic routes and provide a helpful not-found page with links back to your main sections. Check that redirects are single hops, and that server errors do not return 200.
8. Internal links and crawlability
- Use the Link component or plain anchors with real href values, so crawlers can follow them.
- Do not rely on click handlers or router.push for navigation you want indexed.
- Make sure every important page is linked from somewhere reachable, not just the sitemap.
- Use descriptive anchor text rather than "click here".
How to test all of this
Step 1: View the raw HTML
Confirm the H1, main text, links and JSON-LD are present without running scripts.
Step 2: Use Search Console URL Inspection
Check the rendered HTML, the detected canonical and whether the page is indexed.
Step 3: Run the Rich Results Test and a schema validator
Confirm structured data parses without errors.
Step 4: Check PageSpeed Insights field data
Look at the real-user Core Web Vitals, not only the lab score.
Step 5: Crawl your own site
Look for broken links, redirect chains, duplicate titles and pages missing from the sitemap.
If you would like this audited on your own site, our SEO team runs exactly this checklist, and you can book a free strategy call to start. Getting the foundations right also helps everything covered in our post on how AI search engines choose what to cite.
Technical SEO checklist: common questions
Technical SEO gets pages crawled; content gets them ranked. See our guide to writing blog posts that rank in Google and AI search. Planning a rebuild? Follow our website redesign SEO checklist so you keep the rankings you already have.
Is Next.js good for SEO?
Yes, when used well. It can send fully rendered HTML, manage metadata on the server, generate sitemaps and optimize fonts and images. It does not guarantee good SEO by itself, since problems like duplicate URLs, missing canonicals and heavy client-side rendering are still possible.
Can Google index client-side rendered React?
Google can render JavaScript, but it is a slower second step and can fail on heavy or broken scripts. Server-rendered or statically generated HTML is safer and faster to index, and is also friendlier to other crawlers that may not run JavaScript.
How do I set a canonical URL in Next.js?
Use the alternates.canonical field in the Metadata API, with an absolute HTTPS URL that matches your preferred hostname and trailing-slash format. Use generateMetadata for dynamic routes.
What are good Core Web Vitals scores?
Google treats LCP of 2.5 seconds or less, INP of 200 milliseconds or less and CLS of 0.1 or less as good, measured on real-user data at the 75th percentile.
Do I need structured data for SEO?
It is not required to rank, but it helps search engines and other machines understand what a page is. Add types that match the page, keep them accurate and validate them, but do not expect every type to produce a rich result.