Google no longer uses rel=next/prev for indexing. Paginated series—product listings, forum threads, and multi-part content—therefore cannot rely on those tags to explain the sequence. Google's current pagination guidance treats each pagination URL as a separate page.
Google treats each pagination URL as a separate page while trying to recognise the relationship from links and URL structure. The implementation goal is not to force every page into one canonical. It is to give each useful page a stable URL and let crawlers reach the entire sequence.
What replaces rel=next/prev
Use standard <a href> links from one page to the next, keep page numbers in crawlable URLs, and give each page its own canonical URL. Link individual pages back to the first page where that helps users understand the collection. Google does not click “load more” buttons or rely on URL fragments to discover additional pages.
Filter and alternate-sort URLs need a separate decision. If they reproduce the same collection in many orders, use noindex or robots rules deliberately for those variations; do not apply a blanket rule to normal pagination. Remember that robots rules control crawling while noindex requires the URL to remain crawlable long enough for the directive to be read.
View-all page with canonical consolidation
A view-all page can be a good user experience when it is fast and genuinely contains the same complete material. In that specific case, the paginated fragments may canonicalise to the view-all equivalent:
<!-- on /article/page/2/ -->
<link rel="canonical" href="https://example.com/article/all-parts" />
<!-- on /article/page/3/ -->
<link rel="canonical" href="https://example.com/article/all-parts" />
In Laravel, this means creating a dedicated view-all route and adjusting per-page canonicals:
// routes/web.php
Route::get('/article/all-parts', [ArticleController::class, 'viewAll']);
Route::get('/article/page/{page}', [ArticleController::class, 'page']);
// ArticleController
public function page($page)
{
$article = Article::findOrFail(request('id'));
$totalPages = ceil($article->body_word_count / 1000);
return view('articles.page', [
'article' => $article,
'page' => $page,
'totalPages' => $totalPages,
'canonical' => $page === 1
? $article->url
: route('article.view-all', $article->slug),
]);
}
The view-all page must be a practical, complete equivalent. Do not choose it merely to simplify canonicals if its size makes the page unreliable for users.
Self-referencing canonicals with strong interlinking
For product listings where a view-all page is impractical (20,000 products), use self-referencing canonicals per page with strong internal linking between pages:
<!-- on /products?page=1 -->
<link rel="canonical" href="https://example.com/products" />
<!-- on /products?page=2 -->
<link rel="canonical" href="https://example.com/products?page=2" />
Each page canonicalises to itself. Link every page in the sequence back to the first page where that helps users and makes the beginning of the collection clear. Avoid a design where page 2 can link only to pages 1 and 3 across a sequence of thousands; add bounded page-number or range links so deeper sets are not reachable through one enormous chain alone.
This is the default pattern for product and archive pagination. Each page exposes a different subset of items, so each gets a self-referencing canonical. Do not noindex deep pages merely because page 1 is the preferred search landing page; crawlers may need those pages to discover the items listed there.
Infinite scroll with crawlable URLs
Infinite scroll needs a crawlable paginated series underneath it. history.pushState can preserve a user's position, but it does not make a URL discoverable by itself. Render ordinary links to the next and previous pages in the initial HTML:
function InfiniteProductList({ initialProducts }) {
const [products, setProducts] = useState(initialProducts);
const [page, setPage] = useState(1);
async function loadMore() {
const nextPage = page + 1;
const newProducts = await fetch(`/api/products?page=${nextPage}`);
setProducts(prev => [...prev, ...newProducts]);
setPage(nextPage);
// Update URL so Googlebot sees crawlable pagination
window.history.pushState(
{ page: nextPage },
'',
`/products/page/${nextPage}`
);
}
return (
<div>
{products.map(p => <ProductCard key={p.id} product={p} />)}
<button type="button" onClick={loadMore}>Load more</button>
<nav aria-label="Pagination">
{page > 1 && <a href={`/products/page/${page - 1}`}>Previous</a>}
<a href={`/products/page/${page + 1}`}>Next</a>
</nav>
</div>
);
}
The links provide a usable fallback and a discovery path. Every linked URL must return the corresponding subset when requested directly; a URL that always renders page 1 is not real pagination.
Deciding which pattern to use
| Content type | Pattern | Why |
|---|---|---|
| Long articles with a fast equivalent view-all page | View-all may be canonical | The canonical really contains the complete equivalent content |
| Multi-part editorial content | Self-referencing pages with descriptive titles | Each section has a stable landing URL and distinct purpose |
| Product listings | Self-referencing pages with sequential links | Crawlers can reach products beyond page 1 |
| Forum threads | Self-referencing pages | Page URLs remain stable for permalinks and sharing |
| Infinite scroll | Crawlable paginated URLs plus progressive enhancement | Smooth UX with a real linked sequence underneath |
Test page 1, page 2, a middle page, the last page, one page beyond the end, and malformed values. For each valid page, verify the status, self-canonical, unique item set, crawlable next/previous links, and direct-load behavior. The over-limit page should return a real 404.
Pagination without rel=next/prev is not a crisis. Give every page a stable URL, a self-referencing canonical unless a true equivalent warrants consolidation, and ordinary links that let users and crawlers move through the sequence.