nuqs

Adapters

Using nuqs in your React framework of choice

Since version 2, you can now use nuqs in the following React frameworks, by wrapping it with a NuqsAdapter context provider:

Next.js

App router

Wrap your {children} with the NuqsAdapter component in your root layout file:

src/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>
  )
}

Pages router

Wrap the <Component> page outlet with the NuqsAdapter component in your _app.tsx file:

src/pages/_app.tsx
import type { AppProps } from 'next/app'
import { NuqsAdapter } from 'nuqs/adapters/next/pages'
 
export default function MyApp({ Component, pageProps }: AppProps) {
  return (
    <NuqsAdapter>
      <Component {...pageProps} />
    </NuqsAdapter>
  )
}

Unified (router-agnostic)

If your Next.js app uses both the app and pages routers and the adapter needs to be mounted in either, you can import the unified adapter, at the cost of a slightly larger bundle size (~100B).

import { NuqsAdapter } from 'nuqs/adapters/next'

The main reason for adapters is to open up nuqs to other React frameworks:

React SPA

Example, with Vite:

src/main.tsx
import { NuqsAdapter } from 'nuqs/adapters/react'
 
createRoot(document.getElementById('root')!).render(
  <NuqsAdapter>
    <App />
  </NuqsAdapter>
)

Note: because there is no known server in this configuration, the shallow: false option will have no effect.

Since nuqs@2.4.0, you can specify a flag to perform a full-page navigation when updating query state configured with shallow: false, to notify the web server that the URL state has changed, if it needs it for server-side rendering other parts of the application than the static React bundle:

src/main.tsx
createRoot(document.getElementById('root')!).render(
  <NuqsAdapter fullPageNavigationOnShallowFalseUpdates>
    <App />
  </NuqsAdapter>
)

This may be useful for servers not written in JavaScript, like Django (Python), Rails (Ruby), Laravel (PHP), Phoenix (Elixir) etc…

Remix

app/root.tsx
import { NuqsAdapter } from 'nuqs/adapters/remix'
 
// ...
 
export default function App() {
  return (
    <NuqsAdapter>
      <Outlet />
    </NuqsAdapter>
  )
}

React Router v6

src/main.tsx
import { NuqsAdapter } from 'nuqs/adapters/react-router/v6'
import { createBrowserRouter, RouterProvider } from 'react-router-dom'
import App from './App'
 
const router = createBrowserRouter([
  {
    path: '/',
    element: <App />
  }
])
 
export function ReactRouter() {
  return (
    <NuqsAdapter>
      <RouterProvider router={router} />
    </NuqsAdapter>
  )
}

Only BrowserRouter is supported. There may be support for HashRouter in the future (see issue #810), but support for MemoryRouter is not planned.

React Router v7

app/root.tsx
import { NuqsAdapter } from 'nuqs/adapters/react-router/v7'
import { Outlet } from 'react-router'
 
// ...
 
export default function App() {
  return (
    <NuqsAdapter>
      <Outlet />
    </NuqsAdapter>
  )
}

Deprecation notice

The generic import nuqs/adapters/react-router (pointing to v6) is deprecated and will be removed in nuqs@3.0.0.

Please pin your imports to the specific version, eg: nuqs/adapters/react-router/v6 or nuqs/adapters/react-router/v7.

The main difference is where the React Router hooks are imported from: react-router-dom for v6, and react-router for v7.

TanStack Router

src/routes/__root.tsx
import { NuqsAdapter } from 'nuqs/adapters/tanstack-router'
import { Outlet, createRootRoute } from '@tanstack/react-router'
 
export const Route = createRootRoute({
  component: () => (
    <>
      <NuqsAdapter>
        <Outlet />
      </NuqsAdapter>
    </>
  ),
})

TanStack Router support is experimental and does not yet cover TanStack Start.

Type-safe routing via validateSearch

TanStack Router comes with built-in type-safe search params support, and its APIs should likely be used in your application code for best DX.

Nevertheless, sometimes you may need to import a component that uses nuqs (from NPM or a shared library), and benefit from TanStack Router’s type-safe routing.

You may do so via the Standard Schema support:

import { createFileRoute, Link } from '@tanstack/react-router'
import {
  createStandardSchemaV1,
  parseAsIndex,
  parseAsString,
  useQueryStates
} from 'nuqs'
 
const searchParams = {
  searchQuery: parseAsString.withDefault(''),
  pageIndex: parseAsIndex.withDefault(0),
}
 
export const Route = createFileRoute('/search')({
  component: RouteComponent,
  validateSearch: createStandardSchemaV1(searchParams, {
    partialOutput: true
  })
})
 
function RouteComponent() {
  // Consume nuqs state as usual:
  const [{ searchQuery, pageIndex }] = useQueryStates(searchParams)
  // But now TanStack Router knows about it too:
  return (
    <Link
      to="/search"
      search={{
        searchQuery: 'foo',
        // note: we're not specifying pageIndex
      }}
    />
  )
}

Note that the partialOutput flag allows specifying only a subset of the search params for a given route. It also does not reflect those search in the URL automatically, following nuqs’ behaviour more closely.

Caveats

Due to differences in how TanStack Router and nuqs handle serialisation and deserialisation (global in TanStack Router and per-key in nuqs), only trivial state types are supported for type-safe linking. Those include all string-based parsers (string, enum, literals), number-based (integer, float, number literal), boolean, and JSON.

The urlKeys feature to provide shorthand key names is also not supported for similar reasons.

Testing

Documentation for the NuqsTestingAdapter is on the testing page.

On this page