Миграция от Pages Router към App Router в Next.js 15: пълен плейбук (2026)
Поетапен плейбук за миграция от Pages Router към App Router в Next.js 15: 7 фази, оценка в човекодни, codemods, и решения на честите проблеми от 10 реални миграции.
Миграция от Pages Router към App Router в Next.js 15 е поетапен процес, при който двата рутера работят паралелно в един проект, докато преместите маршрутите един по един. За среден по размер продукт (50–150 страници) реалистично говорим за 3 до 8 седмици разработка. Не се налага „big bang" пренаписване: App Router живее в директорията app/, Pages Router в pages/, и Next.js избира правилния рутер за всяка URL заявка. В този плейбук показвам конкретния ред на стъпките, оценка в човекодни, и типичните препъникамъни, които съм срещал при мигрирането на около десет production екипа през последните две години.
App Router и Pages Router работят едновременно в един проект, така че миграцията е инкрементална, а не пренаписване от нулата.
Vercel официално препоръчва App Router от Next.js 14 нататък, но Pages Router не е deprecated и получава поправки на бъгове.
Средна оценка на усилието: 0.5–1 човекоден на прост маршрут, 2–4 човекодни на сложен маршрут с автентикация и данни.
getServerSideProps се пренаписва като async Server Component; getStaticProps се замества от generateStaticParams плюс fetch кеширане.
API Routes стават Route Handlers (route.ts); API-то е почти същото, но методите се експортират по HTTP глагол.
Най-често срещаните blockers: библиотеки без "use client" съвместимост, персонализиран _document.tsx, и NextAuth v4 middleware.
Защо да мигрирате към App Router през 2026 г.
Vercel вложи почти всички нови функции на Next.js в App Router след версия 13.4: React Server Components, Server Actions, Partial Prerendering, поточна доставка със Suspense, вграден Metadata API. Pages Router все още получава поправки на бъгове и не е официално deprecated, но новите API-та не пристигат там. Ако през 2026 г. започвате нов екран с интерактивна модална форма, PPR оптимизация или сложна SEO логика, вие пишете същата функционалност с два пъти повече код в Pages Router.
Втората причина е производителност. В сравнителни бенчмаркове с моите екипи, миграцията към App Router даде 30–55% намаление на клиентския JavaScript bundle, защото Server Components не се изпращат в браузъра. Ако вече използвате Bundle Analyzer в Next.js 15, ще видите цифрите директно след първите няколко мигрирани маршрута. Третата причина е екипна: наемане на React разработчици през 2026 г. без опит с Server Components става все по-трудно, а App Router е това, което младите инженери познават.
Кога не трябва да мигрирате? Ако вашият проект е чиста SPA обвивка с 10–15 страници, целите ви са за поддръжка, и не планирате нови функции, Pages Router работи чудесно. Миграция заради самата миграция е загуба на време. Но ако продуктът расте, ако търсите PPR или Server Actions, или ако правите редизайн, обединете миграцията с редизайна и си спестете две отделни разработки.
Pages Router vs App Router: сравнителна таблица
Ето най-краткото сравнение на двата рутера по осите, които реално ще ви струват време при миграцията:
Аспект
Pages Router
App Router
Директория
pages/
app/
Файл за маршрут
pages/blog/[slug].tsx
app/blog/[slug]/page.tsx
Данни на сървъра
getServerSideProps
async Server Component
Статично рендиране
getStaticProps + getStaticPaths
generateStaticParams + fetch cache
API endpoints
pages/api/*.ts
app/api/*/route.ts (Route Handlers)
Layout
_app.tsx + _document.tsx
app/layout.tsx (вложени layouts)
SEO meta
next/head
Metadata API (export const metadata)
Мутации
Client-side fetch към API route
Server Actions
Стрийминг
Не се поддържа
Suspense + PPR
Клиентска логика
Всичко е клиентско по подразбиране
Server по подразбиране, opt-in с "use client"
Обърнете внимание на последния ред. Това е ментална промяна, която обърква повечето екипи в първите две седмици. В App Router компонент без "use client" изобщо не се появява в браузъра. Ако обвивате нещо с useState или useEffect без директивата, ще получите build error. Този един ред е причината, поради която App Router намалява bundle-а, но и причина за 80% от миграционните бъгове.
Предпоставки и одит преди старта
Преди първата смяна на файл, минете през този одит. Това е един-два дни работа, който спестява седмици.
Версии: нужни са Next.js 14.2 или по-нова (аз препоръчвам 15.x за нови проекти), React 18.3 или React 19, и Node.js 18.18+. Обновяването на Next.js от 12 или 13 на 15 се върши с npx @next/codemod@latest upgrade latest, което пуска official codemods за deprecated API-та. Пуснете го веднъж, комитнете, тествайте, и едва тогава започнете същинската миграция.
Инвентар на маршрутите: направете списък на всички файлове в pages/ и класирайте всеки по три белега: има ли getServerSideProps, ползва ли клиентски state, ползва ли _document.tsx персонализации. Прости статични страници (about, terms) мигрирайте първи, те са тренировка. Оставете страниците с автентикация и forms за средата на миграцията, когато екипът вече знае patterns.
Аудит на зависимостите: проверете дали вашите UI библиотеки (MUI, Chakra, Radix) имат съвместимост със Server Components. Повечето са добавили "use client" на всички компоненти, които го нуждаят, но по-стари версии не са. За NextAuth задължително обновете на v5 (Auth.js), защото v4 middleware не работи с App Router по същия начин.
Поетапен план за миграция (7 фази)
Този план съм използвал при екипи от 3 до 15 разработчици. Фаза 1–2 отнемат около 20% от общото усилие, но са критични.
Фаза 1: Създайте app/layout.tsx
Създайте директория app/ и файл app/layout.tsx. Това е root layout, който заменя _document.tsx и обвивката от _app.tsx:
Веднага след създаването на този файл, Next.js започва да сервира App Router за всеки маршрут в app/. Съществуващите страници в pages/ продължават да работят, защото няма конфликт.
Фаза 2: Мигрирайте най-простата статична страница
Изберете страница без данни и без state, типично /about или /privacy. Създайте app/about/page.tsx и копирайте JSX от pages/about.tsx. Изтрийте стария файл. Deploy-нете. Този цикъл ви дава увереност, че setup-ът работи.
Фаза 3: Мигрирайте страници с getStaticProps
Тези са относително лесни, защото App Router кешира fetch заявките по подразбиране. Заменете getStaticProps с директно await fetch() в Server Component. За динамични маршрути с getStaticPaths, ползвайте generateStaticParams. Ако искате повече контрол върху кеша, погледнете и пълното ръководство за кеширане в Next.js 15.
Фаза 4: Мигрирайте страници с getServerSideProps
Средно сложни. Server Component с fetch(url, { cache: 'no-store' }) възпроизвежда семантиката. Ако страницата ползва cookies или headers, извикайте cookies() или headers() от next/headers.
Фаза 5: Пренапишете API Routes като Route Handlers
Пренесете от pages/api/ в app/api/. Различията са малки. Виж следващата секция.
Фаза 6: Мигрирайте автентикация и middleware
Ако ползвате NextAuth, обновете на v5. Middleware файлът остава в root, но payload-ът се променя. Практически съвети виждате в моето ръководство за middleware и edge runtime.
Фаза 7: Пренапишете мутации като Server Actions
Това е последната фаза, защото е и най-голямата ментална промяна. Клиентски forms, които правеха fetch('/api/save', ...), вече ползват <form action={saveAction}>, където saveAction е server function. За детайли виж ръководството за Server Actions.
Как се мигрира getServerSideProps?
getServerSideProps в Pages Router връщаше { props }, които React компонентът получаваше. В App Router еквивалентът е самата page.tsx да бъде async функция, Server Component, който сам извиква fetch. Няма отделна функция; логиката за данни е вътре в компонента.
// app/products/[id]/page.tsx
export default async function ProductPage({
params,
}: {
params: Promise<{ id: string }>
}) {
const { id } = await params
const res = await fetch(`https://api.example.com/products/${id}`, {
cache: 'no-store', // SSR поведение като getServerSideProps
})
const product = await res.json()
return <h1>{product.name}</h1>
}
Важна промяна в Next.js 15: params и searchParams вече са Promise, не обект. Ако мигрирате от Next.js 14, обновете сигнатурите. За четене на cookies или headers ползвате await cookies() и await headers() от next/headers, които са също async в Next.js 15. Официалните upgrade notes за Next.js 15 изброяват всички breaking changes.
От API Routes към Route Handlers
Route Handlers са App Router еквивалент на API Routes, но с по-чиста семантика. Вместо един файл, който обработва всички HTTP методи в един handler с req.method switch, всеки HTTP глагол е отделна експортирана функция.
Преди (Pages Router):
// pages/api/users.ts
import type { NextApiRequest, NextApiResponse } from 'next'
export default function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === 'GET') {
return res.json({ users: [] })
}
if (req.method === 'POST') {
const body = req.body
return res.status(201).json({ created: true })
}
res.setHeader('Allow', ['GET', 'POST'])
return res.status(405).end()
}
Автоматично Next.js връща 405 за неподдържани методи, така че не е нужно да ги обработвате. Обект NextRequest е базиран на Web стандартния Request, което означава, че кодът е по-преносим между runtimes (Node.js, Edge, Deno). Body четете с await req.json() вместо req.body.
Ако имате API route, който сервира не-JSON (например файл или stream), в App Router връщате new Response(stream, { headers: ... }). Route Handlers могат да работят на Edge Runtime. Добавете export const runtime = 'edge', ако искате по-ниска латенция и не разчитате на Node.js API-та.
_app, _document и next/head → layout и Metadata API
_app.tsx и _document.tsx изчезват. Тяхната роля се поема от app/layout.tsx (root layout) и вложените layouts. За SEO meta тагове, забравете <Head> от next/head. Вместо него ползвате Metadata API.
Ако сте разчитали на global CSS в _app.tsx, преместете import './globals.css' в app/layout.tsx. Providers (Redux, Theme, React Query) обвивайте в отделен client component с "use client" и импортирайте го в root layout.
Чести проблеми и как да ги избегнете
Съставих този списък от post-mortems на около 10 миграции. Ако ги знаете предварително, спестявате седмици. Аз лично се спънах в почти всеки един от тях през първата ми миграция, така че приемете това като хартия за ключова карта.
1. Хидратационни грешки след миграция
Обикновено идват от компоненти, които ползват window, document или localStorage в тялото. В Server Component това е недефинирано на сървъра. Решение: премествате логиката в useEffect, или маркирате компонента като "use client" и добавяте dynamic import с ssr: false за случаи, където няма разумен server fallback.
2. Context providers не работят в Server Components
React Context изисква client boundary. Създайте app/providers.tsx с "use client", обвиващ всичките ви providers, и импортирайте го в root layout. Така целият tree под него е клиентски за context цели, но децата пак могат да бъдат Server Components, ако не консумират context.
3. Библиотеки без "use client" директива
Ако видите build error „Attempted to call ... from the server but ... is on the client", библиотеката ползва React hooks без директива. Wrap-нете import-а в собствен client component, който re-експортира API-то. Отчетете issue в repo-то на библиотеката.
4. Проблеми с CSS-in-JS (styled-components, Emotion)
Класическите CSS-in-JS решения не работят добре със Server Components, защото инжектират стилове по време на render. Решенията: Tailwind CSS (най-безпроблемно), CSS Modules, или конкретни SSR adapter-и за styled-components v6+. Ако проектът ви е тежко зависим от Emotion, оценете миграцията на 2–4 допълнителни седмици.
5. next/link има различно поведение
В App Router, <Link> не изисква child <a> тег. <Link href="/foo">Text</Link> работи директно. Ако мигрирате от старо приложение с <Link href="/foo"><a>Text</a></Link> синтаксис, пуснете codemod npx @next/codemod@latest new-link ..
6. Confusing поведение на generateStaticParams
По подразбиране, ако генерирате статични пътища с generateStaticParams и потребител посети път извън списъка, Next.js прави on-demand ISR. Ако искате 404 за неизвестни пътища, добавете export const dynamicParams = false.
Оценка в човекодни по тип маршрут
Тези числа са усреднени от 10 миграции, за екипи с 6–12 месеца React опит. Прибавете 30% буфер, ако екипът за пръв път вижда Server Components.
Тип маршрут
Пример
Оценка (човекодни)
Статична страница без данни
/about, /privacy
0.25
Статичен списък с getStaticProps
/blog
0.5
Динамичен маршрут с getStaticPaths
/blog/[slug]
1
SSR страница с getServerSideProps
/dashboard
1–2
API route → Route Handler
/api/users
0.5
Автентикация (NextAuth v4 → v5)
Middleware + login
3–5
Форма с мутация → Server Action
/settings
1–3
Custom _document с skript tag инжекции
Analytics setup
1–2
i18n с next-intl миграция
Всички маршрути
5–10
За среден по размер SaaS с около 60 маршрута, 15 API routes и NextAuth, реалистична обща оценка е 25–40 човекодни (5–8 седмици за един fulltime разработчик, или 2–3 седмици за екип от 3-ма paralelen). Планирайте code freeze за нови features през последната седмица от миграцията, иначе новите функции ще бъдат писани в стария рутер и удвояват работата. Пълният официален migration guide на Next.js е чудесен reference за конкретни API mapping-и.
Често задавани въпроси
Мога ли да ползвам App Router и Pages Router едновременно?
Да. Next.js поддържа двата рутера в един проект: файлове в app/ ползват App Router, файлове в pages/ ползват Pages Router. Заявката се маршрутизира по директория. Това позволява инкрементална миграция без прекъсване на production.
Deprecated ли е Pages Router в Next.js 15?
Не. Pages Router получава поправки на бъгове и security updates, и няма обявена дата за премахване. Но нови функции (Server Actions, PPR, вграден Metadata API) идват само в App Router. Vercel препоръчва App Router за нови проекти от Next.js 13.4 нататък.
Колко време отнема миграция от Pages Router към App Router?
За среден SaaS с 50–150 маршрута реалистичната оценка е 3–8 седмици при екип от 2–4 разработчици. Малки проекти (под 20 страници) отнемат 1–2 седмици. Тежко зависими от CSS-in-JS или сложна автентикация: прибавете 30–50% буфер.
Какво се чупи при миграция към App Router?
Най-често: библиотеки без "use client" директива, custom _document.tsx инжекции, NextAuth v4 middleware, styled-components без v6+ SSR adapter, и компоненти, които директно докосват window в render тялото. 80% от проблемите се появяват в първата седмица.
Трябва ли да мигрирам към App Router през 2026 г.?
Мигрирайте, ако: планирате нови features, искате по-малък JS bundle, или ползвате PPR/Server Actions. Не мигрирайте, ако: проектът е в maintenance режим, ползва тежко styled-components, или няма budget за 3–8 седмици разработка. „Миграция заради миграция" е загуба.
Как да настроите Auth.js v5 (NextAuth) в Next.js 15 със self-hosted автентикация, Drizzle adapter, OAuth провайдъри, JWT сесии и защитени маршрути с middleware.
Практически гид за @next/bundle-analyzer в Next.js 15. Как да намалите First Load JS с 40-75% чрез optimizePackageImports, next/dynamic и правилни Server Components граници. С реални цифри от production одити.
Пълно ръководство за Turbopack в Next.js 15: активиране за production, конфигурация в next.config.ts, монорепо setup с Turborepo, миграция от Webpack и troubleshooting на реални проблеми от production.