Next.jsでクエリパラメータを型安全に扱うnuqs

2025/12/01

はじめに

この記事はCommune Developers Advent Calendar 2025シリーズ2の1日目の記事です。今後も続々と記事が公開されるので、ぜひ他の記事もご覧ください!

Commune Developers - Qiita Advent Calendar 2025 - QiitaCalendar page for Qiita Advent Calendar 2025 regarding Commune Developers.
favicon of https://qiita.com/advent-calendar/2025/communeqiita.com
ogp of https://qiita-user-contents.imgix.net/https%3A%2F%2Fcdn.qiita.com%2Fassets%2Fpublic%2Fadvent_calendar%2Fogp%2Fcalendar-ogp-background-c24e7570f8dc39b6f4e1323cbd83d11f.jpg?ixlib=rb-4.0.0&w=1200&mark-x=142&mark-y=128&mark64=aHR0cHM6Ly9xaWl0YS11c2VyLWNvbnRlbnRzLmltZ2l4Lm5ldC9-dGV4dD9peGxpYj1yYi00LjAuMCZ0eHQtYWxpZ249bGVmdCUyQ3RvcCZ0eHQtY29sb3I9JTIzRkZGRkZGJnR4dC1mb250PUhpcmFnaW5vJTIwU2FucyUyMFc2JnR4dC1zaXplPTU2JnR4dD1Db21tdW5lJTIwRGV2ZWxvcGVycyUyMEFkdmVudCUyMENhbGVuZGFyJTIwMjAyNSZ3PTkxNiZoPTM1NiZzPTc5ZWFkYjFhM2M3NmU3ZDljNGQzYmM4ZmRkYTcyMWQx&blend-mode=normal&blend-x=142&blend-y=491&blend64=aHR0cHM6Ly9xaWl0YS11c2VyLWNvbnRlbnRzLmltZ2l4Lm5ldC9-dGV4dD9peGxpYj1yYi00LjAuMCZ0eHQtYWxpZ249bGVmdCUyQ3RvcCZ0eHQtY29sb3I9JTIzRkZGRkZGJnR4dC1mb250PUhpcmFnaW5vJTIwU2FucyUyMFc2JnR4dC1zaXplPTM2JnR4dD0lNDBuZXd0YXJvMjQmdz05MTYmcz1jMjIwOGE3MmIyY2M4Zjg1NmNmMzJmNGM0YmEzODhkMw&s=a5499a086bec505cedbc92d06e090cd3

nuqsとは

nuqsは、様々なReactフレームワークでURLのクエリパラメータを型安全に扱うためのライブラリです。もちろんNext.js App Routerでも使用できます。

nuqsではこんなことができます。

  • 型安全性: TypeScriptの型推論により、クエリパラメータの型が自動的に推論される
  • 簡潔な記法: useStateのような直感的なAPIでクエリパラメータを操作できる
  • パーサーの組み込み: 数値、真偽値、配列など、様々な型のパーサーが用意されている
  • Next.js App Router対応: Next.js 13以降のApp Routerに完全対応
  • Server Components対応: サーバーコンポーネントでもクエリパラメータを扱える

nuqsの使い方

初期設定

Next.js App Routerでnuqsを使うためには、まずNuqsAdapterでアプリケーション全体をラップする必要があります。

app/layout.tsx
import { NuqsAdapter } from 'nuqs/adapters/next/app'
import { type ReactNode } from 'react'
 
export default function RootLayout({
  children
}: {
  children: ReactNode
}) {
  return (
    <html>
      <body>
        <NuqsAdapter>{children}</NuqsAdapter>
      </body>
    </html>
  )
}

Client Componentsでの使い方

app/page.tsx
"use client";
 
import { useQueryState } from "nuqs";
 
export default function Page() {
const [name, setName] = useQueryState('name')
  return (
    <>
      <input value={name || ''} onChange={e => setName(e.target.value)} />
      <button onClick={() => setName(null)}>Clear</button>
      <p>Hello, {name || 'anonymous visitor'}!</p>
    </>
  )
}

これだけで、クエリパラメータの扱いがだいぶ楽になりました。しかし、クエリパラメータでstring以外の型を扱いたい時がありますね。例えば数値を扱いたい時はどうすればいいでしょうか?

URLのクエリパラメータは基本的にstring型です。しかし、parserと呼ばれるものを利用することで、クエリパラメータを型安全に扱うことができます。 numberbooleanのようなプリミティブな型を扱うビルトインのparserから、より複雑な型を扱える独自のカスタムparserを作成することもできます。

'use client';
 
import { useQueryState, parseAsInteger } from 'nuqs'
 
export default function Page() {
  const [count, setCount] = useQueryState('count', parseAsInteger)
  //     ^? number | null
  return (
    <>
      <pre>count: {count}</pre>
      <button onClick={() => setCount(0)}>Reset</button>
      {/* handling null values in setCount is annoying: */}
      <button onClick={() => setCount(c => (c ?? 0) + 1)}>+</button>
      <button onClick={() => setCount(c => (c ?? 0) - 1)}>-</button>
      <button onClick={() => setCount(null)}>Clear</button>
    </>
  )
}

またdefault valueを設定することもできます。これは、クエリパラメータが存在しない場合に使用され、nullではなくdefault valueが使用されます。

const [count, setCount] = useQueryState('count', parseAsInteger.withDefault(0))
//     ^? number

Server Componentsでの使い方

Next.jsのPageコンポーネントで受け取るSearchParamsも、下記のようにloaderを作成することで型安全に取得できます。

search-params.ts
import { parseAsString, parseAsInteger, createLoader } from 'nuqs/server'
 
const searchParams = {
  search: parseAsString.withDefault(''),
  page: parseAsInteger.withDefault(0)
}
 
export const loadSearchParams = createLoader(searchParams)
app/page.tsx
import { loadSearchParams } from './search-params'
import type { SearchParams } from 'nuqs/server'
 
type PageProps = {
  searchParams: Promise<SearchParams>
}
 
export default async function Page({ searchParams }: PageProps) {
  const { search, page } = await loadSearchParams(searchParams)
  return <SearchForm
    search={search}
    page={page}
  />
}

nuqsの便利なオプション

nuqsでは様々なオプションが用意されています。中でも私がよく使う・便利だと感じたオプションを2つ紹介します。

Options | nuqsConfiguring nuqs
favicon of nuqs.dev
ogp of https://nuqs.dev/og/options.jpg

shallow

デフォルトではtrueです。これは、クエリパラメータが変更された時に、ページをリロードするかどうか(ネットワークリクエストを発生させるかどうか)を指定します。Next.js App Routerでクエリパラメータ変更時にRSCを更新したい時はshallow: falseを指定します。そうすることで、クエリパラメータが変更された時にRSCを更新することができます。

limitUrlUpdates

URLの更新回数を制限するオプションです。throttledebounceの2種類があります。今回はキーワード検索などでよく利用するdebounceの使用例を紹介します。

'use client';
 
import { useQueryState, parseAsString, debounce } from 'nuqs';
 
function Search() {
  const [search, setSearch] = useQueryState(
    'q',
    parseAsString
      .withDefault('')
      .withOptions({ shallow: false })
  )
 
  return (
    <input
      value={search}
      onChange={(e) =>
        setSearch(e.target.value, {
          // リセット時は即時更新、それ以外は500msでdebounce
          limitUrlUpdates: e.target.value === '' ? undefined : debounce(500)
        })
      }
      onKeyPress={(e) => {
        if (e.key === 'Enter') {
          // 即時更新
          setSearch(e.target.value)
        }
      }}
    />
  )
}

これにより、リセット時は即時更新、それ以外は500msでdebounceされるようになります。また、先ほど紹介したshallow: falseを併用することで、クエリパラメータが変更された時にRSCを更新でき、検索結果をリアルタイムに反映することができます。

まとめ

nuqsはReactアプリケーションでURLクエリパラメータを型安全に扱うためのライブラリです。基本的な使い方やよく使うオプションを紹介しましたが、他にも様々な機能が用意されています。Reactアプリケーションでクエリパラメータを型安全に扱いたい方は、ぜひ一度試してみてください。

Happy coding!

参考リンク

nuqs | Type-safe search params state management for ReactType-safe search params state management for React. Like useState, but stored in the URL query string.
favicon of nuqs.dev
ogp of https://nuqs.dev/opengraph-image.jpg?opengraph-image.a5d79aa5.jpg