How to get query string parameters in Next.js
Technology

How to get query string parameters in Next.js

If `router.query` examples keep breaking on you, the problem is usually that you're mixing App Router and Pages Router APIs. Here is the exact fix for each case.

2026-06-06
6 min read
How to get query string parameters in Next.js

How to get query string parameters in Next.js#

The symptom is simple: you open /dashboard?search=invoice&page=2, copy an old snippet, and get undefined, stale values, or the wrong API entirely.

The root cause is that Next.js now has two routing models, and the correct query-string API depends on where you read the params:

  • App Router Server Component page: use the searchParams prop
  • App Router Client Component: use useSearchParams()
  • Shared client component across both routers: useSearchParams() still works

Here is the exact fix for each case.

The App Router server-side fix#

If you are inside app/.../page.tsx, use the page prop. In the current Next.js docs, searchParams is a promise in modern App Router pages.

tsx
// app/dashboard/page.tsx
export default async function Page({
  searchParams,
}: {
  searchParams: Promise<{ [key: string]: string | string[] | undefined }>
}) {
  const { search = '', page = '1' } = await searchParams

  return (
    <main>
      <h1>Dashboard</h1>
      <p>Search: {search}</p>
      <p>Page: {page}</p>
    </main>
  )
}

Use this when the query string affects data fetching, pagination, filtering, or metadata for the page itself.

The App Router client-side fix#

If the component is interactive and already marked 'use client', use useSearchParams() from next/navigation.

tsx
'use client'

import { useSearchParams } from 'next/navigation'

export default function SearchSummary() {
  const searchParams = useSearchParams()
  const search = searchParams.get('search') ?? ''
  const page = searchParams.get('page') ?? '1'

  return (
    <p>
      Searching for <strong>{search || 'everything'}</strong> on page {page}
    </p>
  )
}

Two details matter:

  1. useSearchParams() is read-only.
  2. In the App Router docs, Next.js explicitly recommends the page searchParams prop if you are already in a Server Component page.

The shared-component pattern that survives both routers#

This is the cleanest answer if you are migrating gradually or sharing a search bar between pages/ and app/.

tsx
'use client'

import { useSearchParams } from 'next/navigation'

export function SearchBar() {
  const searchParams = useSearchParams()

  if (!searchParams) {
    return <input defaultValue="" placeholder="Search..." />
  }

  const search = searchParams.get('search') ?? ''

  return <input defaultValue={search} placeholder="Search..." />
}

That fallback is important in Pages Router prerendering. The official Pages Router docs now document useSearchParams from next/navigation as a shared option across both routers.

The mistake that keeps causing confusion#

Most search results still mix old Pages Router answers with new App Router code.

If you copied something like this into app/page.tsx:

tsx
// Wrong mental model for a modern App Router page
const query = router.query.search

you are using the wrong abstraction. In the App Router, the page itself should usually read searchParams, and client components should use useSearchParams.

Which API should you choose?#

Use the page prop when:

  • the param changes the server query
  • the param affects SEO or pagination
  • the page should render from the URL alone

Use useSearchParams() when:

  • the component is client-only
  • you need live access after client navigation
  • you are building a reusable search or filter widget

The production-safe rule#

If the URL controls what data the page loads, read it on the server first and pass stable values downward. That keeps your route easy to reason about and avoids a lot of hydration and loading-state noise.

If you are already untangling router differences, these are worth reading next:

References#

Frequently Asked Questions

|

Have more questions? Contact us

Written by

Mahdi Br
Mahdi Br

Full-Stack Dev — Next.js & Supabase

Solo developer building SaaS products with Next.js and Supabase. Writing about production patterns the official docs skip.

Remote

One email a month — no fluff

RLS gotchas, Next.js cache debugging, and the one Supabase setting that bit me last month.