Master URL State Management in React with Nuqs: A Complete Guide
This article introduces the Nuqs library for React, explaining how it synchronizes application state with the browser URL, outlines its key features, provides step‑by‑step installation and usage examples—including query hooks, type‑safe parsers, transition handling, multiple query states, and server‑side parsing—enabling developers to build more intuitive front‑end applications.
Nuqs is a powerful library designed to manage React application state via URL query strings, keeping the state synchronized with the browser address bar for a seamless user experience.
Key Features
Framework Compatibility : Supports Next.js (app and pages routers), plain React (SPA), Remix, and React Router.
URL as Source of Truth : Ensures the URL reflects the current application state, making sharing and bookmarking easy.
History Management : Allows replacing or appending history entries to enable or disable back navigation through state changes.
Built‑in Parsers : Provides parsers for common data types (integer, float, boolean, date) and options to create custom parsers.
Server‑Side Support : Offers type‑safe access to search parameters in server components.
Getting Started with Nuqs
Install the library via npm or yarn:
<code>npm install nuqs</code> <code>yarn add nuqs</code>After installation, integrate Nuqs into your React app using the appropriate adapter for your framework.
Basic Usage
useQueryState Hook
The useQueryState hook is the core of Nuqs, allowing you to manage a single query parameter as a state variable.
<code>import { useQueryState } from 'nuqs';
const GreetingComponent = () => {
const [name, setName] = useQueryState('name');
return (
<>
<h1>Hello, {name || 'Anonymous Visitor'}!</h1>
<input value={name || ''} onChange={e => setName(e.target.value)} />
<button onClick={() => setName(null)}>Clear</button>
</>
);
};</code>In this example, the name parameter stays in sync with the input field and appears in the URL.
Parsing Non‑String Types
By default, search parameters are strings, but Nuqs provides type‑safe parsers such as parseAsInteger and parseAsBoolean to handle numbers, booleans, and dates.
<code>import { useQueryState, parseAsInteger } from 'nuqs';
const CounterComponent = () => {
const [count, setCount] = useQueryState('count', parseAsInteger.withDefault(0));
return (
<>
<pre>count: {count}setCount(c => c + 1)}>+
setCount(c => c - 1)}>-
); };
This ensures the count value is always treated as an integer.
Handling Loading State with Transitions
You can combine useQueryState with React's useTransition to show a loading state during server‑side re‑renders.
<code>// lib/hooks/useProductParams.ts
import { useTransition } from 'react';
export function useProductParams() {
const [isPending, startTransition] = useTransition();
const [search, setSearch] = useQueryState('search',
parseAsString.withDefault('').withOptions({
// ...options
startTransition
})
);
const [{ category, sort, page }, setParams] = useQueryStates({
// ...params
}, { startTransition });
return { isPending, search, setSearch, category, sort, page, setParams };
}
</code>Use the hook in a component to display a spinner while isPending is true.
<code>'use client'
import { useProductParams } from '@/lib/hooks/useProductParams';
import LoadingSpinner from './LoadingSpinner';
export default function SearchBar() {
const { search, setSearch, isPending } = useProductParams();
return (
<div className="relative">
{/* ...other UI */}
{isPending && (
<div className="absolute right-2 top-2">
<LoadingSpinner />
</div>
)}
</div>
);
}
</code>Advanced Techniques
Using Multiple Query States
When managing related query parameters together, useQueryStates is ideal:
<code>import { useQueryStates, parseAsFloat } from 'nuqs';
const LocationComponent = () => {
const [coordinates, setCoordinates] = useQueryStates({
lat: parseAsFloat.withDefault(45.18),
lng: parseAsFloat.withDefault(5.72)
});
return (
<div>
Latitude: {coordinates.lat}, Longitude: {coordinates.lng}
</div>
);
};
</code>Server‑Side Parsing
Nuqs can also manage server‑side search parameters, useful for deeply nested server components.
<code>import { createSearchParamsCache, parseAsInteger } from 'nuqs/server';
export const searchParamsCache = createSearchParamsCache({
maxResults: parseAsInteger.withDefault(10)
});
function ResultsPage({ searchParams }) {
const { maxResults } = searchParamsCache.parse(searchParams);
return <span>Showing up to {maxResults} results</span>;
}
</code>Summary
Nuqs transforms how React applications manage URL query string state, turning the URL into a reliable data source and simplifying complex state‑management scenarios, enabling developers to build more intuitive and user‑friendly front‑end applications.
Code Mala Tang
Read source code together, write articles together, and enjoy spicy hot pot together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.