Announcing nuqs version 2
nuqs

SEO

Pitfalls and best practices for SEO with query strings

If your page uses query strings for local-only state, you should add a canonical URL to your page, to tell SEO crawlers to ignore the query string and index the page without it.

In the Next.js app router, this is done via the metadata object:

import type { Metadata } from 'next'
 
export const metadata: Metadata = {
  alternates: {
    canonical: '/url/path/without/querystring'
  }
}

If however the query string is defining what content the page is displaying (eg: YouTube’s watch URLs, like https://www.youtube.com/watch?v=dQw4w9WgXcQ), your canonical URL should contain relevant query strings, and you can still use your parsers to read it:

/app/watch/page.tsx
import type { Metadata, ResolvingMetadata } from 'next'
import { notFound } from "next/navigation";
import { createParser, parseAsString, type SearchParams } from 'nuqs/server'
 
type Props = {
  searchParams: Promise<SearchParams>
}
 
// Normally you'd reuse custom parsers across your application,
// but for this example we'll define it here.
const youTubeVideoIdRegex = /^[^"&?\/\s]{11}$/i
const parseAsYouTubeVideoId = createParser({
  parse(query) {
    if (!youTubeVideoIdRegex.test(query)) {
      return null
    }
    return query
  }
  serialize(videoId) {
    return videoId
  }
})
 
export async function generateMetadata({
  searchParams
}: Props): Promise<Metadata> {
  const videoId = parseAsYouTubeVideoId.parseServerSide((await searchParams).v)
  if (!videoId) {
    notFound()
  }
  return {
    alternates: {
      canonical: `/watch?v=${videoId}`
    }
  }
}