프레임워크난이도 어려움⏱ 며칠~몇 주(앱 규모에 따라)
Next.js Pages Router에서 App Router로 마이그레이션
Pages Router→App Router
요약: app/ 디렉터리를 pages/와 공존시키며 라우트 단위로 점진 이전하는 것이 정석입니다. getServerSideProps는 서버 컴포넌트의 직접 fetch로, _app/_document는 layout으로 바뀝니다.
왜 옮기나
- App Router는 React Server Components, 중첩 레이아웃, 스트리밍, 부분 프리렌더링(PPR)을 지원합니다.
- Pages Router는 유지되지만 신규 기능은 App Router 중심으로 추가됩니다.
- 레이아웃 중첩·로딩/에러 바운더리가 파일 규약으로 깔끔해집니다.
전제 — 현재 상태
pages/ 디렉터리, getServerSideProps/getStaticProps, _app.js·_document.js, next/router 사용.
마이그레이션 단계
1
app/과 pages/ 공존 시작
app/ 디렉터리를 만들고 같은 라우트가 양쪽에 없게만 하면 둘이 공존합니다. 한 번에 다 옮기지 말고 라우트 단위로 이전합니다.
mkdir app2
root layout 작성
_app.js·_document.js의 역할을 app/layout.js의 <html><body>가 대신합니다. 전역 Provider·폰트·메타도 여기로 옮깁니다.
// app/layout.js
export default function RootLayout({ children }) {
return <html lang="ko"><body>{children}</body></html>
}3
페이지를 page.js로
pages/about.js → app/about/page.js. 기본은 서버 컴포넌트이며, 브라우저 훅(useState 등)을 쓰면 파일 최상단에 use client를 선언합니다.
4
데이터 패칭 전환
getServerSideProps/getStaticProps 대신 서버 컴포넌트에서 async/await로 직접 fetch합니다. 캐시는 fetch 옵션(no-store/revalidate)으로 제어합니다.
export default async function Page() {
const data = await fetch(url, { next: { revalidate: 60 } }).then(r => r.json())
return <List data={data} />
}5
라우팅 훅 교체
next/router의 useRouter를 next/navigation으로 바꿉니다. query는 useSearchParams/useParams로 분리됩니다.
import { useRouter, useSearchParams } from 'next/navigation'⚠️ 막히는 케이스 · 함정
- use client 컴포넌트 안에서는 서버 전용 코드(직접 DB 접근 등)를 쓸 수 없습니다 — 경계를 명확히.
- getInitialProps·_document의 커스텀 로직은 App Router에 직접 대응이 없어 재설계가 필요합니다.
- next/router import는 App Router에서 동작하지 않습니다(next/navigation으로).
- 메타데이터는 generateMetadata로 옮기며, Head 컴포넌트 대신 metadata export를 씁니다.
✅ 검증: 이전한 라우트마다 SSR/CSR 동작, 데이터 패칭, 메타데이터(canonical/og)를 빌드 후 확인하고, pages/와 app/이 같은 경로를 중복 정의하지 않는지 점검합니다.
Next.jsApp RouterPages RouterServer ComponentsRSC