مهاجرت از Pages Router به App Router در Next.js 15: پلیبوک کامل با تخمین زمان (۲۰۲۶)
راهنمای عملی مهاجرت از Pages Router به App Router در Next.js 15 با تخمین واقعی زمان بر اساس اندازه پروژه، تبدیل کد getServerSideProps و API Routes، و راهحل مشکلات رایج hydration و کش.
مهاجرت از Pages Router به App Router در Next.js 15 برای پروژههای کوچک بین ۳ تا ۵ روز کاری و برای پروژههای بزرگ (بیش از ۱۰۰ روت) بین ۳ تا ۶ هفته زمان میبرد، اما لازم نیست همه چیز را یکجا مهاجرت کنید؛ این دو روتر میتوانند در کنار هم و در یک پروژه به صورت تدریجی زندگی کنند. من در یک سال گذشته پنج تیم را از Pages Router به App Router منتقل کردهام و در این پلیبوک، مسیر مرحله به مرحله، تخمینهای واقعی زمان، و همه دامهایی که هر تیم درگیرشان شد را جمعبندی کردهام تا شما مجبور نباشید دوباره آنها را کشف کنید.
App Router جایگزینی اجباری نیست؛ Pages Router در Next.js 15 همچنان پشتیبانی میشود و میتوانید هر دو را در یک پروژه اجرا کنید.
تخمین واقعی: ۳ تا ۵ روز برای زیر ۲۰ روت، ۲ تا ۳ هفته برای ۲۰ تا ۱۰۰ روت، و ۳ تا ۶ هفته برای بیش از ۱۰۰ روت (به همراه بازنویسی تستها).
getServerSideProps به fetch با cache: 'no-store' در Server Component تبدیل میشود؛ getStaticProps به fetch با next: { revalidate }.
API Routes همچنان کار میکنند اما در App Router با Route Handlers جایگزین میشوند که امضای Request/Response استاندارد Web دارند.
Middleware بین دو روتر مشترک است و نیاز به تغییر ندارد. راستش را بخواهید، این سادهترین بخش مهاجرت است.
سنگینترین بخش مهاجرت، بازنویسی هوکهای وابسته به useRouter از next/router به سه هوک جدید useRouter, usePathname, و useSearchParams از next/navigation است.
آیا در سال ۲۰۲۶ باید به App Router مهاجرت کنم؟
پاسخ صادقانه من: بستگی دارد، و این یک پاسخ فرار نیست. اگر اپلیکیشن شما یک پروژه کوچک با کمتر از ۲۰ صفحه است که در Pages Router به خوبی کار میکند، هزینهفرصت مهاجرت را در برابر مزایای واقعی وزن کنید. اما اگر تیم شما در حال ساخت قابلیتهای جدید است، اگر به Partial Prerendering علاقه دارید، اگر از React Server Components برای کم کردن حجم باندل کلاینت استفاده میکنید، یا اگر میخواهید Streaming و Suspense را به شکل مدرن به کار ببرید، مهاجرت را جدی بگیرید.
در Next.js 15، تیم Vercel بهروزرسانیهای جدید Pages Router را عملاً متوقف کرده؛ همه ویژگیهای جدید (Server Actions، Partial Prerendering، تازهسازی کش پیشرفته، و بهینهسازیهای Turbopack) روی App Router متمرکز است. بنابراین Pages Router در وضعیت «نگهداری» قرار دارد، نه رشد. طبق راهنمای رسمی مهاجرت Next.js، App Router مسیر پیشنهادی برای تمام پروژههای جدید است.
تخمین زمان مهاجرت بر اساس اندازه پروژه
در تجربه من با پنج مهاجرت واقعی در بیزنسهای تولیدی، این جدول تخمین دقیقی از زمان مورد نیاز است (با فرض یک توسعهدهنده تماموقت با تجربهی Next.js):
اندازه پروژه
تعداد روت
زمان مهاجرت (روز کاری)
نکته
کوچک
کمتر از ۲۰
۳ تا ۵ روز
معمولاً یکجا مهاجرت میشود.
متوسط
۲۰ تا ۵۰
۷ تا ۱۲ روز
مهاجرت تدریجی توصیه میشود.
بزرگ
۵۰ تا ۱۰۰
۱۲ تا ۲۰ روز
حتماً روت به روت مهاجرت کنید.
خیلی بزرگ
۱۰۰ به بالا
۳ تا ۶ هفته
یک نفر full-time اختصاصی نیاز است.
این اعداد شامل بازنویسی تستهای کامپوننتها هم میشوند، که معمولاً حدود ۳۰٪ کل زمان مهاجرت را میگیرد. اگر تستهای شما با React Testing Library روی رندر کلاینتی نوشته شدهاند، انتظار بازنویسی مقادیر قابل توجهی از آنها را داشته باشید. Server Component ها را نمیتوان با render() کلاسیک تست کرد و به Playwright یا Vitest با محیط سرور نیاز خواهید داشت.
نکته مهم دیگر: مهاجرت CSS Modules ساده است، اما اگر از styled-jsx به شکل گسترده در _document.tsx استفاده کردهاید، برنامهی جایگزینی به CSS-in-JS مدرن مثل vanilla-extract یا Tailwind را داشته باشید، چون بسیاری از کتابخانههای CSS-in-JS سرورساید هنوز با RSC مشکل دارند.
مقایسه Pages Router و App Router
قبل از رفتن سراغ کد، بگذارید یک مقایسهی منصفانه از این دو روتر داشته باشیم. من طرفدار هیچ کدام نیستم؛ هر کدام مصالحههای خودشان را دارند:
ویژگی
Pages Router
App Router
روش رندر پیشفرض
Client Component + hydration
Server Component
واکشی داده
getServerSideProps, getStaticProps
fetch در Server Component + کش
API ها
API Routes (pages/api)
Route Handlers (app/api/route.ts)
Layout ها
_app.tsx و nested manually
layout.tsx در هر پوشه
مدیریت خطا
Error Boundaries دستی
error.tsx, not-found.tsx
Loading UI
State های دستی
loading.tsx + Suspense
مانیپولاسیون داده
API + fetch در کلاینت
Server Actions
Metadata و SEO
next/head
Metadata API
پشتیبانی از PPR
خیر
بله
حجم باندل کلاینت
معمولاً بیشتر
معمولاً ۲۰ تا ۴۰٪ کمتر
منحنی یادگیری
ملایمتر (مدل ذهنی آشنا)
تندتر (مفاهیم RSC جدید)
در گذشته، Pages Router به دلیل مدل ذهنی سادهتر، انتخاب من برای نمونههای اولیه سریع بود. اما در سال ۲۰۲۶، App Router به بلوغ رسیده و کش سازی و Server Actions به شکلی که در Pages Router هرگز ممکن نبود، توسعه را سریعتر میکنند. برای درک عمیقتر مدل کشسازی و Server Actions، مقالهی واکشی داده، کشینگ و Server Actions در Next.js 15 را بخوانید. اگر PPR هم برایتان جذاب است، راهنمای Partial Prerendering در Next.js 15 نقطهی شروع خوبی است.
آیا Pages Router و App Router میتوانند همزمان اجرا شوند؟
بله، و این ویژگی کلیدی است که مهاجرتهای واقعی را ممکن میکند. Next.js اجازه میدهد پوشههای pages/ و app/ در یک پروژه کنار هم باشند. روتها بر اساس اولویت رفع میشوند: اگر یک روت هم در app/ و هم در pages/ تعریف شده باشد، App Router برنده است.
my-nextjs-app/
├── app/
│ ├── layout.tsx # روت جدید در App Router
│ ├── page.tsx # صفحهی اصلی جدید
│ └── dashboard/
│ └── page.tsx # /dashboard مهاجرت شده
├── pages/
│ ├── _app.tsx # هنوز استفاده میشود برای روتهای pages
│ ├── about.tsx # /about هنوز در Pages Router
│ ├── products/
│ │ └── [id].tsx # /products/:id هنوز در Pages Router
│ └── api/
│ └── legacy.ts # API قدیمی همچنان کار میکند
└── middleware.ts # مشترک بین دو روتر
استراتژی توصیهشده من: از صفحاتی که کمترین ترافیک را دارند شروع کنید (مثلاً صفحه About، Contact، Privacy Policy)، مکانیزم استقرار را با هر مهاجرت تست کنید، و بعد بروید سراغ صفحات پرترافیک. این رویکرد ریسک را کم میکند و به تیم اجازه میدهد الگوها را در یک محیط ایمن یاد بگیرد.
تبدیل _app.tsx و _document.tsx به layout.tsx
در Pages Router، فایل _app.tsx برای provider ها و _document.tsx برای اسکلت HTML به کار میرفت. در App Router، هر دوی اینها با یک فایل واحد app/layout.tsx جایگزین میشوند:
نکته مهم: ThemeProvider احتمالاً به context React نیاز دارد و بنابراین باید Client Component باشد. آن را در فایلی جداگانه با 'use client' در بالا تعریف کنید و از layout سرورساید مصرف کنید. این الگوی «مرز کلاینت را حداکثر پایین بکش» یکی از مهمترین اصول App Router است — Provider ها را در یک کامپوننت کلاینتی جدا کنید تا محتوای صفحه بتواند Server Component بماند.
تبدیل getServerSideProps و getStaticProps
این معمولاً بیشترین بخش کد را در طول مهاجرت تغییر میدهد. خبر خوب: کد نتیجه معمولاً کوتاهتر و خواناتر است. یک مقایسهی سریع:
برای getStaticProps، به جای cache: 'no-store' از next: { revalidate: 3600 } استفاده کنید. اگر پارامترهای دینامیک دارید که در زمان بیلد باید تولید شوند، به جای getStaticPaths از تابع generateStaticParams استفاده کنید:
در Next.js 15، توجه داشته باشید که params و searchParams اکنون Promise هستند. این یک تغییر breaking نسبت به Next.js 14 است و باید await شوند (اولین باری که این را دیدم، چند دقیقه گیج شدم چرا params خالی است). اگر میخواهید مدل ذهنی عمیقتری از کش سازی داشته باشید، راهنمای واکشی داده و کشینگ ما توضیح میدهد که چه زمانی از no-store، force-cache، یا revalidate استفاده کنید.
مهاجرت API Routes به Route Handlers
API Routes در Pages Router هنوز کار میکنند و در App Router توسط Route Handlers جایگزین میشوند. تفاوت اصلی: Route Handlers از استانداردهای Web (Request و Response) استفاده میکنند، نه از شیء اختصاصی Next.js. این یعنی کد شما قابل حملتر است و میتواند در Edge Runtime، Cloudflare Workers، یا Deno هم اجرا شود.
// قبل: pages/api/users/[id].ts
import type { NextApiRequest, NextApiResponse } from 'next'
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const { id } = req.query
if (req.method === 'GET') {
const user = await db.user.findUnique({ where: { id: String(id) } })
return res.status(200).json(user)
}
if (req.method === 'DELETE') {
await db.user.delete({ where: { id: String(id) } })
return res.status(204).end()
}
return res.status(405).json({ error: 'Method not allowed' })
}
معادل آن به شکل Route Handler:
// بعد: app/api/users/[id]/route.ts
import { NextResponse } from 'next/server'
export async function GET(
_req: Request,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params
const user = await db.user.findUnique({ where: { id } })
return NextResponse.json(user)
}
export async function DELETE(
_req: Request,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params
await db.user.delete({ where: { id } })
return new Response(null, { status: 204 })
}
در Route Handlers، به جای بررسی req.method، برای هر method HTTP یک تابع export میکنید. Method های پشتیبانینشده بهطور خودکار پاسخ 405 برمیگردانند. این تفکیک تمیزتر است و type safety بهتری میدهد. اگر میخواهید عمق بیشتری از این الگو و ترکیبش با middleware داشته باشید، مقالهی میدلور Next.js 15 و الگوهای پیشرفته ما را بخوانید.
جایگزینی next/head با Metadata API
یکی از تمیزترین بهبودهای App Router، Metadata API است. به جای مدیریت دستی <title> و <meta> در هر صفحه با next/head، متادیتا را به شکل declarative export میکنید:
Metadata API یک مزیت مهم دارد: کش fetch بین generateMetadata و کامپوننت صفحه به اشتراک گذاشته میشود. یعنی اگر در هر دو تابع، getProduct(id) را صدا بزنید، فقط یک بار درخواست شبکه انجام میشود. برای جزئیات کامل، به مستندات رسمی generateMetadata مراجعه کنید.
تبدیل useRouter و ناوبری کلاینتساید
این احتمالاً بخشی است که بیشترین باگهای سکوتآمیز را در مهاجرتهای من ایجاد کرده. در Pages Router، هوک useRouter از next/router همه چیز را برمیگرداند: pathname, query, push(), و رویدادها. در App Router، این ویژگیها بین سه هوک تقسیم شدهاند و همه از next/navigation import میشوند:
تفاوتهای مهم دیگر: رویدادهای router (مثل routeChangeStart) دیگر وجود ندارند و به جای آنها از تغییرات pathname و searchParams در یک useEffect استفاده کنید. متد router.reload() با router.refresh() جایگزین شده که کش سرور را هم تازه میکند. و router.push() دیگر یک آبجکت { pathname, query } نمیگیرد؛ فقط یک URL رشتهای میگیرد.
مشکلات رایج و راهحلها
اینها متداولترین مشکلاتی هستند که تیمهای من در مهاجرت با آنها برخورد کردهاند:
خطاهای Hydration پس از مهاجرت
معمولاً چون یک Client Component سعی میکند window, localStorage, یا document را در فاز اولیه رندر مصرف کند. راه حل: به useEffect منتقل کنید، یا از الگوی dynamic import با ssr: false استفاده کنید (فقط از Client Component ها). طبق مستندات React 19، خطاهای hydration اکنون پیامهای واضحتری با اشاره به عنصر مشکلساز نمایش میدهند.
Context در Server Components کار نمیکند
Context API فقط در Client Component ها کار میکند. اگر state سراسری در Server Component لازم است، به جای آن از cookies، searchParams، یا الگوی «cache function» React 19 استفاده کنید. اگر واقعاً به context نیاز دارید، Provider را به عنوان Client Component بسازید و در layout.tsx بگذارید.
باگهای کشسازی غیرمنتظره
Next.js 15 مدل کشسازی جدیدی دارد که رفتار پیشفرض را از agressive-cache به sensible-defaults تغییر داده. اگر دادههای شما به شکل غیرمنتظره کش نمیشوند (یا برعکس)، استراتژی کش هر route را به شکل صریح تعیین کنید: export const revalidate = 60 یا export const dynamic = 'force-dynamic'. این بخش را جدی بگیرید — من دو بار در ماه اول مهاجرت به این خاطر باگ داشتم.
CSS-in-JS از کار میافتد
کتابخانههای CSS-in-JS runtime-based (مثل styled-components و emotion) نیاز به config خاص برای SSR در App Router دارند. من پیشنهاد میکنم به Tailwind، CSS Modules، یا vanilla-extract مهاجرت کنید؛ اینها با RSC سازگارتر هستند و باندل کوچکتری تولید میکنند. برای پروژههای بزرگ، این تصمیم میتواند یک هفته به مهاجرت اضافه کند اما ارزشش را دارد.
تستها خراب میشوند
Server Components async هستند و با jest-environment-jsdom استاندارد کار نمیکنند. به Vitest با @testing-library/react نسخه ۱۶+ مهاجرت کنید، یا برای صفحات مهم E2E test با Playwright بنویسید. برای منطق تجاری خالص که هیچ ربطی به React ندارد، تستهای واحد را میتوانید نگه دارید.
سوالات متداول
آیا Pages Router در Next.js 15 منسوخ شده است؟
نه، Pages Router هنوز کاملاً پشتیبانی میشود و در Next.js 15 هیچ اعلان deprecation رسمی برایش داده نشده. اما توسعهی ویژگیهای جدید (Server Actions, PPR, Turbopack اختصاصی) روی App Router متمرکز است، بنابراین Pages Router در حالت «نگهداری» قرار دارد.
آیا App Router سریعتر از Pages Router است؟
در بیشتر موارد، بله. App Router به دلیل Server Components باندل کلاینت کوچکتری تولید میکند (معمولاً ۲۰ تا ۴۰٪ کمتر)، Streaming واقعی از سرور به کلاینت را ممکن میکند، و از Partial Prerendering پشتیبانی میکند که TTFB (Time To First Byte) را به شکل چشمگیری کاهش میدهد.
آیا میتوانم API Routes قدیمی را نگه دارم و فقط صفحات را مهاجرت کنم؟
بله، این یک استراتژی رایج و توصیهشده است. API Routes در pages/api/ کار خود را ادامه میدهند حتی وقتی همهی صفحات به app/ منتقل شدهاند. میتوانید بعداً و در فاز جداگانهای، API Routes را به Route Handlers مهاجرت کنید.
Middleware چطور؟ آیا نیاز به تغییر دارد؟
خیر، فایل middleware.ts در ریشهی پروژه بین Pages Router و App Router مشترک است و روی هر دو نوع روت اجرا میشود. این سادهترین بخش مهاجرت است و تقریباً کاری برای انجام نیست.
آیا next-i18next با App Router کار میکند؟
خیر، next-i18next فقط برای Pages Router طراحی شده. برای App Router باید به کتابخانهی next-intl یا next-international مهاجرت کنید. اگر میخواهید سریع شروع کنید، راهنمای i18n در Next.js 15 با next-intl و پشتیبانی RTL ما را بخوانید.
Turbopack در Next.js 15 برای dev پایدار و برای build در بتا است. این راهنما فعالسازی، پیکربندی turbopack در next.config، مهاجرت گامبهگام از Webpack و بنچمارک واقعی روی پروژهی e-commerce را با کد عملی پوشش میدهد.
راهاندازی کامل بینالمللیسازی در Next.js 15 App Router با next-intl، تشخیص خودکار زبان، رندر استاتیک، hreflang و پشتیبانی RTL برای فارسی و عربی همراه با مثالهای واقعی.