using-nuqs
Manage React state in URL query parameters with nuqs. Covers Suspense boundaries, parsers, clearing state, and deep-linkable dialogs.
Best use case
using-nuqs is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Manage React state in URL query parameters with nuqs. Covers Suspense boundaries, parsers, clearing state, and deep-linkable dialogs.
Teams using using-nuqs should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/using-nuqs/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How using-nuqs Compares
| Feature / Agent | using-nuqs | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Manage React state in URL query parameters with nuqs. Covers Suspense boundaries, parsers, clearing state, and deep-linkable dialogs.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Working with nuqs
Manage React state in URL query parameters with nuqs. Covers Suspense boundaries, parsers, clearing state, and deep-linkable dialogs.
## Implement Working with nuqs
Manage React state in URL query parameters with nuqs for shareable filters, search, and deep-linkable dialogs.
**See:**
- Resource: `using-nuqs` in Fullstack Recipes
- URL: https://fullstackrecipes.com/recipes/using-nuqs
---
### Suspense Boundary Pattern
nuqs uses `useSearchParams` behind the scenes, requiring a Suspense boundary. Wrap nuqs-using components with Suspense via a wrapper component to keep the boundary colocated:
```typescript
import { Suspense } from "react";
type SearchInputProps = {
placeholder?: string;
};
// Public component with built-in Suspense
export function SearchInput(props: SearchInputProps) {
return (
<Suspense fallback={<input placeholder={props.placeholder} disabled />}>
<SearchInputClient {...props} />
</Suspense>
);
}
```
```typescript
"use client";
import { useQueryState, parseAsString } from "nuqs";
// Internal client component that uses nuqs
function SearchInputClient({ placeholder = "Search..." }: SearchInputProps) {
const [search, setSearch] = useQueryState("q", parseAsString.withDefault(""));
return (
<input
value={search}
onChange={(e) => setSearch(e.target.value || null)}
placeholder={placeholder}
/>
);
}
```
This pattern allows consuming components to use `SearchInput` without adding Suspense themselves.
### State to URL Query Params
Replace `useState` with `useQueryState` to sync state to the URL:
```typescript
"use client";
import {
useQueryState,
parseAsString,
parseAsBoolean,
parseAsArrayOf,
} from "nuqs";
// String state (search, filters)
const [search, setSearch] = useQueryState("q", parseAsString.withDefault(""));
// Boolean state (toggles)
const [showArchived, setShowArchived] = useQueryState(
"archived",
parseAsBoolean.withDefault(false),
);
// Array state (multi-select)
const [tags, setTags] = useQueryState(
"tags",
parseAsArrayOf(parseAsString).withDefault([]),
);
```
### Clear State
Set to `null` to remove from URL:
```typescript
// Clear single param
setSearch(null);
// Clear all filters
function clearFilters() {
setSearch(null);
setTags(null);
setShowArchived(null);
}
```
When using `.withDefault()`, setting to `null` clears the URL param but returns the default value.
### Deep-Linkable Dialogs
Control dialog visibility with URL params for shareable links:
```typescript
import { Suspense } from "react";
type DeleteDialogProps = {
onDelete: (id: string) => Promise<void>;
};
// Public component with built-in Suspense
export function DeleteDialog(props: DeleteDialogProps) {
return (
<Suspense fallback={null}>
<DeleteDialogClient {...props} />
</Suspense>
);
}
```
```typescript
"use client";
import { useQueryState, parseAsString } from "nuqs";
import { AlertDialog, AlertDialogContent } from "@/components/ui/alert-dialog";
function DeleteDialogClient({ onDelete }: DeleteDialogProps) {
const [deleteId, setDeleteId] = useQueryState("delete", parseAsString);
async function handleDelete() {
if (!deleteId) return;
await onDelete(deleteId);
setDeleteId(null);
}
return (
<AlertDialog open={!!deleteId} onOpenChange={(open) => !open && setDeleteId(null)}>
<AlertDialogContent>
{/* Confirmation UI */}
<Button onClick={handleDelete}>Delete</Button>
</AlertDialogContent>
</AlertDialog>
);
}
```
Open the dialog programmatically:
```typescript
// Open delete dialog for specific item
setDeleteId("item-123");
// Deep link: /items?delete=item-123
```
### Opening Dialogs from Buttons
Use a trigger button to open the dialog:
```typescript
function ItemRow({ item }: { item: Item }) {
const [, setDeleteId] = useQueryState("delete", parseAsString);
return (
<Button variant="ghost" onClick={() => setDeleteId(item.id)}>
Delete
</Button>
);
}
```
---
## References
- [nuqs Documentation](https://nuqs.47ng.com/)
- [nuqs Parsers](https://nuqs.47ng.com/docs/parsers)Related Skills
using-workflows
Create and run durable workflows with steps, streaming, and agent execution. Covers starting, resuming, and persisting workflow results.
using-user-stories
Document and track feature implementation with user stories. Workflow for authoring stories, building features, and marking acceptance criteria as passing.
using-tests
Testing strategy and workflow. Tests run in parallel with isolated data per suite. Prioritize Playwright for UI, integration tests for APIs, unit tests for logic.
using-sentry
Capture exceptions, add context, create performance spans, and use structured logging with Sentry.
using-logging
Use structured logging with Pino throughout your application. Covers log levels, context, and workflow-safe logging patterns.
using-drizzle-queries
Write type-safe database queries with Drizzle ORM. Covers select, insert, update, delete, relational queries, and adding new tables.
using-authentication
Use Better Auth for client and server-side authentication. Covers session access, protected routes, sign in/out, and fetching user data.
using-analytics
Track custom events and conversions with Vercel Web Analytics. Covers common events, form tracking, and development testing.
nuqs-setup
Sync React state to URL query parameters for shareable filters, search queries, and deep links to modal dialogs. Preserves UI state on browser back/forward navigation.
url-state-management
Sync React state to URL query parameters for shareable filters, search, and deep-linkable dialogs with nuqs.
testing
Complete testing setup with Neon database branching, Playwright browser tests, integration tests, and unit tests. Isolated branches with automatic TTL cleanup.
stripe-subscriptions
Complete subscription billing system with Stripe integration, feature flags for plan gating, webhook handling, and billing portal.