SuperAPI AI Directory

nextjs

Frontend & websites

View repository

Updated 10-16 06:43

About this skill

Next.js Routing & Navigation

Requirements

Route Props Helpers (Next.js 15.5+)

  • Use globally available PageProps, LayoutProps, RouteContext types - no imports needed
  • RouteContext: Use for typing route handler context parameters with proper type inference
  • PageProps: Use for page components with typed params and searchParams
  • LayoutProps: Use for layout components with children and parallel route slots
  • Automatically includes typed params, searchParams, children, and parallel route slots
  • Always await Promise-based params and searchParams

Typed Routes (Next.js 15.5+)

  • TypeScript will catch invalid routes in <Link> components at compile time
  • Automatically generates types based on your file structure
  • Use Route type for props
  • Use as Route for non-literal strings (e.g., ('/blog' + slug) as Route)

Custom Param Hooks

  • NEVER use useParams from Next.js directly - use typed alternatives from @/hooks/use-params
  • Use unique param names (e.g., [userId] not [id]) for better type inference
  • useTParams(): For specific app routes with exact typing
  • useLayoutParams(): For layout components, returns all params as optional
  • useLayoutParams(): For layout components with route prefix, exact route params required + prefix params optional

URL Query State

  • NEVER use useSearchParams from Next.js - always use nuqs for URL query state
  • Use appropriate parsers based on parameter data type
  • Configure history mode and clearOnDefault
  • Handle URL updates with void to prevent promise-related linting issues

Examples

return ( Product: {id} 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 }); }

// Usage const [filter, setFilter] = useFilterState(); void setFilter('active');

// Usage in components import Link from 'next/link';

// ✅ Type-safe links

// ✅ Non-literal strings with Route type const slug = 'nextjs';

// ❌ TypeScript will catch invalid routes at compile time

// ✅ 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 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