Scaffolds URL-state filters for Next.js pages using nuqs — generates typed parser maps, client components, server loaders, and tests from a single JSON spec.
How this skill is triggered — by the user, by Claude, or both
Slash command
/pproenca-dot-skills-1:nuqs-scaffolderThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Generate a coherent set of nuqs files from one spec. The skill is **template-driven** — you read the spec, copy the templates, and substitute placeholders. No build step, no codegen runtime; the templates ARE the artifact.
Generate a coherent set of nuqs files from one spec. The skill is template-driven — you read the spec, copy the templates, and substitute placeholders. No build step, no codegen runtime; the templates ARE the artifact.
Use this skill when:
useState filters onto nuqssearchParams.server.ts already exports the schemaIf the codebase has legacy nuqs patterns instead, run the nuqs-codemod-runner skill first.
assets/templates/spec.template.json and fill in name, module, and params. See "Spec Format" below.config.json (overridable per-call).The agent does the rendering — Claude is the templating engine. Each template is annotated with markers (/*= ... =*/) that name the placeholder slot and document the substitution rule.
{
"name": "Search", // PascalCase — drives the exported symbol names
"module": "search", // kebab-case — drives file paths and the "module" folder
"params": {
"q": { "type": "string", "default": "" },
"page": { "type": "integer", "default": 1 },
"limit": { "type": "integer", "default": 10 },
"categories": { "type": "array-of-string-native", "default": [] },
"sort": { "type": "string-literal", "values": ["asc","desc"], "default": "asc" },
"minPrice": { "type": "float", "default": null },
"lastSeen": { "type": "iso-date", "default": null }
}
}
type valuestype | Parser used | Notes |
|---|---|---|
string | parseAsString | |
integer | parseAsInteger | |
float | parseAsFloat | |
boolean | parseAsBoolean | |
iso-date | parseAsIsoDate | Date-only |
iso-date-time | parseAsIsoDateTime | Date + time |
timestamp | parseAsTimestamp | ms since epoch |
hex | parseAsHex | Numeric value, hex URL form |
index | parseAsIndex | 0-based in code, 1-based in URL |
array-of-string | parseAsArrayOf(parseAsString) | ?tags=a,b,c |
array-of-string-native | parseAsNativeArrayOf(parseAsString) | ?tag=a&tag=b — requires nuqs ≥ 2.7 |
string-literal | parseAsStringLiteral(values) | Requires values: string[] |
number-literal | parseAsNumberLiteral(values) | Requires values: number[] |
json | parseAsJson(SchemaName.parse) | Generates a Zod schema stub; mark default separately |
If default is null, the param is nullable; otherwise the template uses .withDefault(...).
| Template | Renders to (default) | Loaded when |
|---|---|---|
searchParams.ts.template | lib/{module}-search-params.ts | Always |
searchParams.server.ts.template | lib/{module}-search-params.server.ts | Always |
filters.tsx.template | components/{module}/{name}-filters.tsx | Always |
filters.test.tsx.template | components/{module}/{name}-filters.test.tsx | If config.generate_tests is true |
spec.json.template | Anywhere — starter for the user | First-run prompt |
Template files end in .template so editors don't apply syntax highlighting to placeholder markers — the original extension is preserved as the suffix-before-.template so you can still tell at a glance what the rendered file will be.
Paths are configurable in config.json — override globs, file naming style (kebab vs PascalCase), and whether tests are emitted.
All templates use the same placeholder syntax. The agent substitutes them in one pass:
| Placeholder | Source | Example |
|---|---|---|
__NAME__ | spec.name | Search |
__name__ | camelCase form of spec.name | search |
__module__ | spec.module | search |
/*= PARSERS =*/ | Iterate spec.params → key: parseAsXxx.withDefault(...) lines | see template |
/*= COMPONENT_FIELDS =*/ | Iterate spec.params → one input/select per type | see template |
/*= TEST_CASES =*/ | Iterate spec.params → one assertion per default | see template |
/*= NULLABLE_IMPORTS =*/ | Add Nullable helper import if any param is nullable | conditional |
/*= ZOD_SCHEMAS =*/ | For json type params, emit a Zod schema stub | conditional |
/*= ... =*/ markers are instructions to the agent, not literal substitutions. Replace the entire marker (including the /*= =*/ delimiters) with the expanded content.
Read references/conventions.md for:
app/config.json is pre-populated with sensible Next.js App Router defaults. Override only if your repo uses different conventions:
{
"lib_dir": "lib",
"components_dir": "components",
"generate_tests": true,
"test_runner": "vitest"
}
On first use, the agent should ask the user for the spec via AskUserQuestion if no spec file is provided.
nuqs — Best-practice reference these templates encode. Read it to understand WHY the templates are shaped this way.nuqs-codemod-runner — Run BEFORE this skill if migrating an existing page from pre-v2.5 nuqs.See gotchas.md for edge cases discovered during use.
npx claudepluginhub joshuarweaver/cascade-code-general-misc-1 --plugin pproenca-dot-skills-1Provides best practices for nuqs type-safe URL query state management in Next.js and React frameworks, covering parsers, setup, server integration, and performance.
Converts JSON specs into full Next.js applications with routes, layouts, SSR, and metadata. Use for AI-generated or declarative multi-page apps.
Implements Next.js App Router with file-system routing, root/nested layouts, templates, loading/error/not-found states, dynamic routes, and generateStaticParams for modern Next.js 13+ apps.