How to Index a Next.js Site (SSR, ISR & Client)

A Next.js deploy finishes in about a minute. Getting the routes it just shipped into Google’s index is a longer job and a different one. If you are working out how to index a Next.js site, the work goes better as a sequence than as a pile of tips: decide which routes belong in the index, make sure each of those arrives as HTML, publish the files that let Google find them, submit, then verify what Google kept. This guide walks that sequence in order, with the framework-specific trap at each step.
Step 1: Inventory the routes you actually want indexed
Next.js creates URLs cheaply. One [slug] segment can produce thousands of them, and the App Router adds more surface: route groups, pagination params, and filter combinations a client component appends as query strings. Before you submit anything, write down which URLs you want Google to keep.
Most projects sort into three piles. Routes that should be indexed: marketing pages, articles, product and detail pages, category landing pages. Routes that should stay reachable but out of the index: login, checkout steps, thank-you pages, and the long tail of faceted filter URLs. Those take robots: { index: false } in their metadata. Routes Google should not fetch at all: API handlers, preview endpoints, internal tooling, which belong in robots.txt.
Doing this first is not bureaucracy. The alternative is learning which pile a route belongs to after Google has indexed a few thousand of its siblings, and removal is slower work than prevention.
Step 2: Choose the rendering mode per route, not per project
The rule that matters for indexing is short: anything you want indexed should be complete in the initial HTML response. Google does process JavaScript, but its JavaScript SEO documentation describes rendering as a later, separate stage of processing, so content that only exists after the browser runs your bundle waits in a queue and depends on that stage succeeding.
Applied to the four Next.js modes, that means static and server-rendered routes are the safe default for anything public. ISR is fine for content that changes on a known rhythm, as long as the revalidation window is shorter than the freshness you are promising, and as long as first-time requests block for real HTML rather than serving a skeleton. Client-fetched content is the one to avoid on indexable routes: the first response Google sees is an empty shell.
Verify per route rather than trusting the mode you think you configured:
curl -s https://yourdomain.com/products/example | grep -i "<h1"
If your headline is missing from that output, it was missing from Googlebot’s first look too. For the fuller treatment of what each mode puts on the wire, we wrote up what Google sees in SSR, ISR and client-rendered Next.js separately.
Step 3: Generate robots.txt and the sitemap from your route data
Both files are code in Next.js, and they should be. app/robots.ts and app/sitemap.ts are generated at build time from the same source that generates the pages, which means they cannot drift the way a hand-edited file in public/ drifts three refactors later. Google’s guidance on creating a robots.txt applies unchanged; the framework only changes where the file comes from.
For dynamic segments, have sitemap.ts query your database or CMS rather than listing routes by hand. A large catalogue needs one sitemap entry per product, and nobody maintains that list manually. If the site is large, split it: the sitemaps protocol caps a single file at 50,000 URLs and 50MB uncompressed, and Next.js offers generateSitemaps for producing an indexed set.
One caveat. A sitemap is a discovery mechanism: Google’s documentation on building sitemaps treats the entries as hints about which URLs matter, not as instructions to index them.
Step 4: Name the canonical URL once, in absolute form
A Next.js app usually answers on more than one hostname: the production domain, the platform’s generated deployment URL, and every preview build. Add the apex and www variants, plus whatever trailingSlash does to the path, and one page is served identically from half a dozen addresses.
Set alternates: { canonical } in your metadata to an absolute production URL, and make the non-canonical hosts redirect rather than serve copies. Google’s guide to consolidating duplicate URLs explains what happens otherwise: Google picks a canonical itself, and its pick is sometimes the deployment URL you never meant anyone to see.
Step 5: Read the response headers before you submit
This step takes a minute and catches the quiet blockers that would otherwise cost you a fortnight:
curl -sI https://yourdomain.com/your-page
You are looking for X-Robots-Tag: noindex in the headers and for a 200 status. Hosting platforms attach that header to protect preview deployments, headers() in next.config.js can add it deliberately, and middleware can add it conditionally. None of it shows up in view-source, so a page can look perfect in the browser while telling Google to stay away. Follow any redirect chain to its end too, and confirm the URL you plan to submit is the one that finally answers.
Step 6: Submit, using the route that fits the volume
Search Console is the manual route: verify the property, submit the sitemap URL, then use URL Inspection to request a recrawl for individual priority pages. It works well for a handful of URLs and poorly for a launch, because it is one URL at a time against a daily ceiling.
Bulk submission is the route for a deploy that shipped a thousand new product pages. This is where AIndexify fits a Next.js workflow: paste the URLs straight from your generated sitemap or upload a CSV, up to 10,000 URLs per submission, with no Search Console connection or ownership proof required. The preflight also catches what step 5 might have missed, since a URL carrying noindex, a robots block or a 404 comes back as “Couldn’t check” with the credit refunded rather than being quietly submitted into nothing.
Step 7: Verify by template, not by site
Submission is a request. Submitted is not indexed, and with a framework in the middle the gap widens: your build can be green, your local render perfect, and the page still absent from Google’s index a week later.
Check on a schedule, and check per template rather than per site. A Next.js project is a set of route patterns, and blockers arrive at the pattern level: /blog/[slug] is indexed while /products/[id] is not, because one is server-rendered and the other fetches on the client, or because a metadata flag was set in a shared layout. A site-wide indexed count averages that signal away. A per-template count points at the file to open. For the wider process behind all of this, from crawl scheduling through canonical selection, the complete guide to Google indexing is the longer read.
How to index a Next.js site, in short
Ship the routes server-rendered, generate robots.txt and the sitemap from real data, keep one canonical per page, read the headers, then submit and watch. When your next deploy goes out, submit your URLs and see where those routes actually stand, date by date.