nuqs
@beignet/nuqs connects contract query schemas to URL-backed state. Use it for search, filters, tabs, sorting, and pagination when the URL should reflect the current view.
bun add @beignet/nuqs @beignet/react-query @tanstack/react-query nuqsSetup
import { createNuqs } from "@beignet/nuqs";
export const nq = createNuqs();Bind the contract builder directly with nq(contract). The helper reads the
contract query schema and keeps URL state aligned with the same input shape used
by the client.
In Next.js App Router, mount the NuqsAdapter once:
import { NuqsAdapter } from "@beignet/nuqs/next/app";
export function Providers({ children }: { children: React.ReactNode }) {
return <NuqsAdapter>{children}</NuqsAdapter>;
}URL-backed filters
import { useQuery } from "@tanstack/react-query";
import { parseAsString, parseAsStringLiteral } from "nuqs";
import { listContacts } from "@/features/contacts/contracts";
import { nq, rq } from "@/client";
const contactsSearch = nq(listContacts).query({
parsers: {
search: parseAsString,
group: parseAsStringLiteral(["personal", "work", "family", "other"]),
},
history: "replace",
});
function ContactsPage() {
const [filters, setFilters] = contactsSearch.useState();
const query = useQuery(
contactsSearch.toQueryOptions(rq(listContacts), filters, {
query: { limit: 50, offset: 0 },
}),
);
return null;
}toQueryOptions(...) composes with @beignet/react-query, so URL state and query input stay aligned with the same contract.
Query helper options
nq(contract).query(config) requires one property: parsers, a map of nuqs
parsers keyed by the contract's query schema keys. Parser keys are checked
against the contract query shape, and you only declare parsers for the keys
the URL should own — other query params can stay in normal component state or
static query input.
Everything else in config is an optional nuqs useQueryStates option passed
through to the hook: history ("replace" by default, or "push" to create
history entries), shallow, scroll, clearOnDefault, limitUrlUpdates,
startTransition, and urlKeys for renaming search params. See the
nuqs options reference for what each one
does. useState(options) accepts the same options as per-call overrides.