Có — pages/ và app/ cùng tồn tại được, nên bạn migrate dần dần (incremental) thay vì viết lại toàn bộ. Đây là điểm cốt lõi Next.js thiết kế cho việc chuyển đổi.
Quy tắc: nếu một route tồn tại ở cả hai nơi, app/ thắng (build sẽ cảnh báo conflict). Migrate từng route từ lá ra gốc.
Các bước chính:
1. Tạo app/layout.tsx thay cho _app + _document (<html>/<body> chuyển vào đây).
2. Chuyển data fetching: getServerSideProps → fetch trực tiếp trong Server Component; getStaticProps → fetch + generateStaticParams; getStaticPaths → generateStaticParams.
3. next/router → next/navigation (useRouter, usePathname, useSearchParams) trong Client Component.
4. Thêm 'use client' cho component dùng hook/event; phần còn lại mặc định là Server Component.
5. API routes pages/api → Route Handlers app/api/.../route.ts.
Lưu ý: đừng port hàng loạt — migrate route ít rủi ro trước, đo lại, vì semantics caching và rendering của App Router khác hẳn.
Yes — pages/ and app/ can coexist, so you migrate incrementally instead of a full rewrite. This is a core design point of Next.js for the transition.
Rule: if a route exists in both, app/ wins (the build warns on conflicts). Migrate route by route, leaf to root.
Main steps:
1. Create app/layout.tsx to replace _app + _document (move <html>/<body> here).
2. Move data fetching: getServerSideProps → fetch directly in a Server Component; getStaticProps → fetch + generateStaticParams; getStaticPaths → generateStaticParams.
3. next/router → next/navigation (useRouter, usePathname, useSearchParams) in Client Components.
4. Add 'use client' to components using hooks/events; the rest default to Server Components.
5. API routes pages/api → Route Handlers app/api/.../route.ts.
Note: don't bulk-port — migrate low-risk routes first and re-measure, since App Router's caching and rendering semantics differ significantly.