Routing
Next.js uses file-system routing: folders in app/ define URL paths. No router configuration file is needed.
Static Routes
Each folder with a page.tsx becomes a route:
app/
├── page.tsx → /
├── about/page.tsx → /about
└── contact/page.tsx → /contact
Navigation
Use the Link component for client-side navigation without full page reloads:
import Link from 'next/link';
export default function Nav() {
return (
<nav>
<Link href="/">Home</Link>
<Link href="/about">About</Link>
<Link href="/blog">Blog</Link>
</nav>
);
}
For programmatic navigation in Client Components, use useRouter:
'use client';
import { useRouter } from 'next/navigation';
function LoginButton() {
const router = useRouter();
return (
<button onClick={() => router.push('/dashboard')}>
Go to Dashboard
</button>
);
}
Dynamic Routes
Wrap a folder name in brackets to create a dynamic segment:
app/blog/[slug]/page.tsx → /blog/hello-world, /blog/nextjs-routing
// app/blog/[slug]/page.tsx
export default async function BlogPost({
params,
}: {
params: Promise<{ slug: string }>;
}) {
const { slug } = await params;
const post = await getPost(slug);
return (
<article>
<h1>{post.title}</h1>
<p>{post.content}</p>
</article>
);
}
Multiple segments: app/shop/[category]/[product]/page.tsx → /shop/electronics/laptop.
Catch-All Routes
Use [...slug] to match multiple path segments:
app/docs/[...slug]/page.tsx → /docs/a, /docs/a/b, /docs/a/b/c
export default async function DocsPage({
params,
}: {
params: Promise<{ slug: string[] }>;
}) {
const { slug } = await params;
return <h1>Docs: {slug.join(' / ')}</h1>;
}
Optional catch-all: [[...slug]] also matches /docs with no segments.
Route Groups
Parentheses create groups that do not affect the URL:
app/
├── (marketing)/
│ ├── layout.tsx
│ ├── page.tsx → /
│ └── about/page.tsx → /about
└── (dashboard)/
├── layout.tsx
└── dashboard/page.tsx → /dashboard
Use route groups to apply different layouts without changing URLs.
Nested Layouts and 404
Each folder can define its own layout.tsx. Layouts persist across child route navigation.
Call notFound() from next/navigation when a resource does not exist:
import { notFound } from 'next/navigation';
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
const item = await getItem(id);
if (!item) notFound();
return <div>{item.name}</div>;
}
Next: understand Server Components and Client Components.