В чём разница между App Router и Pages Router в Next.js?
Pages Router хранит файлы в pages/, использует getServerSideProps/getStaticProps и клиентские компоненты. App Router (app/) работает на React Server Components, async/await для fetch, вложенных layout.tsx и streaming.
App Router vs Pages Router в Next.js
Next.js поддерживает два подхода к маршрутизации: Pages Router (до Next.js 12 включительно, поддерживается и сейчас) и App Router (введён в Next.js 13, стабилен с 13.4). Они сосуществуют в одном проекте, но имеют принципиально разные модели рендеринга.
Pages Router
Файлы в pages/ автоматически становятся маршрутами. Специальные экспорты управляют рендерингом:
// pages/jobs/[id].tsx
import { GetServerSideProps, GetStaticProps } from 'next';
export const getServerSideProps: GetServerSideProps = async (ctx) => {
const job = await fetchJob(ctx.params!.id as string);
return { props: { job } };
};
export default function JobPage({ job }: { job: Job }) {
return <div>{job.title}</div>;
}
Все компоненты здесь клиентские по умолчанию — гидратация происходит на клиенте. Для API-роутов используется pages/api/*.ts.
App Router
Файлы в app/ следуют новому соглашению. Все компоненты по умолчанию — Server Components (RSC). Клиентские компоненты помечаются директивой 'use client'.
// app/jobs/[id]/page.tsx
import { notFound } from 'next/navigation';
// Компонент — async Server Component, данные fetching прямо внутри
export default async function JobPage({
params,
}: {
params: Promise<{ id: string }>;
}) {
const { id } = await params;
const job = await fetch(`/api/jobs/${id}`, { cache: 'force-cache' }).then(
(r) => r.json()
);
if (!job) notFound();
return <div>{job.title}</div>;
}
// Метаданные через export
export async function generateMetadata({
params,
}: {
params: Promise<{ id: string }>;
}) {
const { id } = await params;
const job = await fetch(`/api/jobs/${id}`).then((r) => r.json());
return { title: job.title };
}
Ключевые отличия
- Рендеринг по умолчанию: Pages Router — клиентские компоненты; App Router — серверные RSC.
- Fetch данных: Pages Router —
getServerSideProps/getStaticProps/getInitialProps; App Router —async/awaitпрямо в компоненте. - Layouts: Pages Router использует
_app.tsxи_document.tsx; App Router — вложенныеlayout.tsx, что позволяет иметь разные лейауты для разных сегментов без перерендеринга. - Streaming / Suspense: App Router встроенно поддерживает
<Suspense>и потоковую передачу HTML; Pages Router требует ручных обходов. - API Routes: Pages Router —
pages/api/; App Router —app/api/route.tsс явным экспортом методовGET,POST, etc. - Middleware: в обеих системах
middleware.tsработает одинаково на уровне edge. - Parallel Routes / Intercepting Routes: доступны только в App Router через соглашения
@slotи(.)route.
Пример Route Handler в App Router
// app/api/jobs/route.ts
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const page = Number(searchParams.get('page') ?? 1);
const jobs = await db.jobs.findMany({ skip: (page - 1) * 20, take: 20 });
return NextResponse.json(jobs);
}
export async function POST(request: Request) {
const body = await request.json();
const job = await db.jobs.create({ data: body });
return NextResponse.json(job, { status: 201 });
}
Подводные камни
- В App Router параметры
paramsиsearchParamsв page.tsx — этоPromiseначиная с Next.js 15; забытьawait paramsприводит к ошибке в runtime. - Server Components не могут использовать хуки (
useState,useEffect) — добавление любого хука требует перейти к'use client', что разрывает RSC-дерево. - Смешивание Pages Router и App Router в одном проекте работает, но общий state и контексты между ними не шарятся — это источник трудноуловимых багов.
cookies()иheaders()изnext/headersдоступны только в Server Components; вызов в клиентском компоненте бросает исключение.- Кэш
fetchв App Router агрессивен по умолчанию (force-cache); без явного{ cache: 'no-store' }илиrevalidateданные могут устареть. - Переход с Pages Router не тривиален:
useRouterизnext/routerне работает в App Router — нуженnext/navigation. - В Pages Router нельзя использовать async Server Components — весь async fetch на уровне страницы только через
getServerSideProps. - Parallel Routes (
@slot) усложняют структуру папок и могут неожиданно сломаться при неправильно расставленныхdefault.tsx.
Common mistakes
- Считать App и Pages взаимозаменяемыми и переносить
getServerSideProps1-в-1 - Импортировать
useRouterизnext/routerвнутриapp/ - Игнорировать асинхронные
params/cookies()в Next.js 15 - Полагать, что
fetchв App всё ещё кешируется по умолчанию
What the interviewer is testing
- Понимает RSC-first природу App Router
- Знает специальные файлы сегмента и роль layouts
- Может назвать конкретные различия в data fetching и API routes
- Осознаёт ограничения смешанного использования