Why it matters
Crawlers that don't run JavaScript stay on the original URL, and Google treats meta refresh/JS redirects as weaker signals than HTTP redirects.
How to fix it
Redirect on the server: redirects() in next.config, redirect()/permanentRedirect() in a Server Component before any Suspense boundary, or a proxy rewrite.
Example
// app/old/page.tsx — server-side, status is a real 308
import { permanentRedirect } from 'next/navigation'
export default function Page() { permanentRedirect('/new') }References
More seo rules
void seo reports 60 rules in this category. What search engines need from the raw response: status codes, titles and descriptions in <head>, self-referencing canonicals, one h1, crawlable links, Open Graph, icons, robots.txt and a sitemap with real dates.
http-statusPage does not return HTTP 200redirect-chainURL reaches its content through more than one redirectredirect-temporaryTemporary redirect (302/303/307) usednoindexIndexable page carries noindexrobots-snippet-restrictednosnippet or a very low max-snippet limits previewssoft-404Missing page returns HTTP 200 (soft 404)html-too-largeUncompressed HTML is over Googlebot's 2 MB fetch limitrsc-payload-ratioInline RSC flight payload dominates the HTML