SyntaxStudy
Sign Up
Next.js File-System Routing in the App Router
Next.js Beginner 1 min read

File-System Routing in the App Router

Next.js App Router uses the file system to define routes. Every folder inside app/ that contains a page.tsx (or page.js) file becomes a publicly accessible route. The URL path mirrors the folder hierarchy: app/dashboard/analytics/page.tsx is accessible at /dashboard/analytics. This convention eliminates the need for a separate router configuration file. Dynamic segments are created by wrapping a folder name in square brackets, such as [id] or [slug]. Inside the page component the dynamic value is accessible via the params prop. Catch-all segments use [...slug] syntax and capture multiple URL segments into an array. Optional catch-all segments use [[...slug]] syntax and also match the route without any segments. The Link component from next/link enables client-side navigation between routes without a full page reload. It prefetches linked pages in the background when they appear in the viewport, making navigation feel instant. The useRouter hook from next/navigation provides programmatic navigation and gives access to the current pathname, search params, and router methods like router.push() and router.replace().
Example
// app/blog/[slug]/page.tsx
// Accessible at /blog/my-first-post, /blog/hello-world, etc.

interface PageProps {
  params: { slug: string };
  searchParams: { [key: string]: string | string[] | undefined };
}

export default function BlogPost({ params, searchParams }: PageProps) {
  return (
    <article>
      <h1>Post slug: {params.slug}</h1>
      <p>Page: {searchParams.page ?? '1'}</p>
    </article>
  );
}

// app/shop/[...categories]/page.tsx
// Matches /shop/clothing, /shop/clothing/shirts, etc.
export default function ShopPage({
  params,
}: {
  params: { categories: string[] };
}) {
  const breadcrumb = params.categories.join(' > ');
  return <h1>{breadcrumb}</h1>;
}

// Client component using Link and useRouter
'use client';
import Link from 'next/link';
import { useRouter } from 'next/navigation';

export default function Nav() {
  const router = useRouter();
  return (
    <nav>
      <Link href="/dashboard">Dashboard</Link>
      <button onClick={() => router.push('/login')}>Login</button>
    </nav>
  );
}