У App Router маршрути визначає структура папок у app/, а спеціальні файли всередині папки задають роль.
app/
├── layout.tsx # кореневий макет (обов'язковий, містить <html> і <body>)
├── page.tsx # /
├── blog/
│ ├── layout.tsx # макет для всіх сторінок /blog/*
│ ├── page.tsx # /blog
│ └── [slug]/
│ ├── page.tsx # /blog/:slug
│ ├── loading.tsx # стан завантаження
│ └── error.tsx # межа помилок
page.tsx - вміст маршруту. Без нього папка не стає доступним URL.
layout.tsx - спільна обгортка для сторінки й усіх вкладених маршрутів:
export default function BlogLayout({ children }: { children: React.ReactNode }) {
return (
<section>
<BlogSidebar />
{children}
</section>
);
}
Ключова властивість макетів: при переході між сторінками всередині макета він не перемонтовується - зберігає стан (відкрита бічна панель, введений пошук) і не рендериться заново. Перемальовується лише змінена частина.
Динамічні сегменти: [slug] - параметр; params у сторінці - Promise, його треба дочекатися:
export default async function Post({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = await params;
const post = await getPost(slug);
return <article>{post.title}</article>;
}
Інші файли:
loading.tsx- автоматичний<Suspense>: запасний вигляд, поки сторінка завантажує дані;error.tsx- межа помилок сегмента (має бути клієнтським компонентом);not-found.tsx- дляnotFound();route.ts- обробник HTTP-запитів (API) замість сторінки.
Групи маршрутів (marketing) - папки в дужках не потрапляють в URL і дають змогу мати різні макети для частин сайту.
За замовчуванням усі ці компоненти - серверні: можна звертатися до бази чи API прямо в компоненті, а 'use client' додається лише там, де потрібна інтерактивність.