with one click
nextjs
Next.js routing with typed routes, PageProps, LayoutProps helpers, and nuqs for URL state. Use for pages, layouts, navigation, and query parameters.
Menu
Next.js routing with typed routes, PageProps, LayoutProps helpers, and nuqs for URL state. Use for pages, layouts, navigation, and query parameters.
Read every doc in www and packages/kitcn/skills/kitcn, sync to active changeset(s), and track with checkmarks.
Use for Convex/kitcn setup and feature work: cRPC, ORM, auth, React.
Work heavyweight framework or library tasks with planning-first research, selective deep analysis, and rigorous handoff
Work a task end-to-end with lean context gathering, implementation, and verification
Generate structured video transcripts from local files or video URLs using Gemini Files API. Use when a GitHub or Linear tracker item, comment, or attachment includes a screen recording, .mov, .mp4, or tracker-hosted video and you need a <video-transcripts> block instead of hand-written notes.
Skill: shadcn-parity
| description | Next.js routing with typed routes, PageProps, LayoutProps helpers, and nuqs for URL state. Use for pages, layouts, navigation, and query parameters. |
| name | nextjs |
| metadata | {"skiller":{"source":".agents/rules/nextjs.mdc"}} |
PageProps, LayoutProps, RouteContext types - no imports needed<Link> components at compile timeRoute type for propsas Route for non-literal strings (e.g., ('/blog' + slug) as Route)@/hooks/use-params[userId] not [id]) for better type inferencereturn (
Category: {category}
// Multiple parameters export async function DELETE( request: Request, ctx: RouteContext<'/api/users/[id]/posts/[postId]'> ) { const { id, postId } = await ctx.params; return Response.json({ userId: id, postId }); }
// Optional parameters export async function PUT( request: Request, ctx: RouteContext<'/api/categories/[[...slug]]'> ) { const { slug } = await ctx.params; // slug: string[] | undefined return Response.json({ segments: slug }); }
// URL Query State with nuqs export const useFilterState = () => { return useQueryState( 'filter', parseAsStringEnum(['all', 'active', 'completed']) .withDefault('all') .withOptions({ history: 'push', clearOnDefault: true }) ); };// Usage const [filter, setFilter] = useFilterState(); void setFilter('active');
// Enable Typed Routes in next.config.ts const nextConfig = { typedRoutes: true, // Compile-time type safety for routes }; export default nextConfig;// Usage in components import Link from 'next/link';
// ✅ Type-safe links
View Patient Browse Library// ✅ Non-literal strings with Route type const slug = 'nextjs';
Blog Post router.push(('/blog/' + slug) as Route);// ❌ TypeScript will catch invalid routes at compile time
Broken Link // ← Type error // Custom Param Hooks Usage import { useTParams, useLayoutParams } from '@/hooks/use-params';// ✅ For specific routes with exact typing const PatientPage = () => { const params = useTParams<'/patients/[patientId]'>(); params.patientId; // string - guaranteed to exist };
// ✅ For layouts - all params optional const RootLayout = ({ children }) => { const params = useLayoutParams(); params.patientId; // string | undefined params.complaintId; // string | undefined };
// ✅ For layouts with route prefix - exact + optional const ComplaintLayout = ({ children }) => { const params = useLayoutParams<'/complaints/[complaintId]'>(); params.complaintId; // string - required for exact match params.someOtherParam; // string | undefined - from related routes };
// ❌ Don't use manual typing for route handlers export async function GET( request: Request, { params }: { params: Promise<{ slug: string }> } ) { const { slug } = await params; return Response.json({ slug }); }// ❌ Don't use manual typing for page props interface Props { params: Promise<{ slug: string }>; children: React.ReactNode; }
// ❌ Don't use raw useParams - use typed alternatives import { useParams } from 'next/navigation'; const params = useParams();
// ❌ Don't use useSearchParams import { useSearchParams } from 'next/navigation'; const searchParams = useSearchParams();
// ❌ Don't use string concatenation for routes
router.push(/patients/${id}); // Use typed routes instead