우당탕탕
Next.js 13 App Router 마이그레이션 하면서 궁금했던 점들 답해봅니다 본문
처음에 Next.js 13 App Router로 프로젝트를 옮기면서 생각보다 삽질을 많이 했어요. 공식 문서도 많이 바뀌고, 기존 페이지 라우팅과 완전히 달라진 부분이 많아서 당황스러웠거든요.
그래서 이번 글에서는 제가 직접 경험하면서 가장 많이 검색하고 고민했던 내용들 위주로 Q&A 형식으로 정리해봤습니다. 마이그레이션 고민하시는 분들께 도움이 될 거예요.
개발 환경 / 버전 정보
제가 사용한 환경은 Node.js 18, Next.js 13.4 버전이에요. 기존에 pages 폴더 기반 라우팅에서 완전히 app 폴더 기반으로 바꾸는 작업이었죠.
Next.js 13 App Router 마이그레이션 후기 관련 정보
Next.js 13 App Router 마이그레이션, 이렇게 하면 됩니다
사실 App Router로 완전 전환하는 게 가장 큰 변화인데요, 기존 pages 디렉토리의 페이지 단위 함수 대신 React Server Component 기반의 구조로 옮겨야 해요.
예를 들어, 기존에 pages/index.js에 있던 코드는 이렇게 바뀝니다:
export default function Home() {
return (
<main>
<h1>Welcome to Next.js 13 App Router!</h1>
</main>
);
}
이걸 app/page.js에 넣는 식으로 바꾸면 돼요. 그 외 추가적으로 layout.js 파일을 통해 레이아웃을 계층적으로 관리하게 되죠.
Next.js 13 App Router 마이그레이션 후기 관련 정보
여기서 많이 헷갈립니다, Q&A 모음
Q. App Router와 기존 Pages Router 완전히 다르던데, 같이 쓸 수는 없나요?
A. 네, Next.js 13부터는 app 폴더와 pages 폴더가 공존 가능합니다. 다만 우선순위는 app이 더 높아서, app에 있는 경로가 우선 렌더링 돼요. 그래도 되도록이면 한 쪽으로 통일하는 걸 추천합니다.
Q. 데이터 페칭을 어떻게 해야 하나요? getServerSideProps는 안 되나요?
A. App Router에서는 getServerSideProps 대신 React Server Component 특성상 컴포넌트 최상단에서 바로 fetch를 사용할 수 있어요. 예를 들어:
export default async function Page() {
const res = await fetch('https://api.example.com/data', { next: { revalidate: 60 } });
const data = await res.json();
return <div>{data.title}</div>;
}
이렇게 하면 서버사이드에서 데이터를 바로 받아서 렌더링됩니다. 그리고 next: { revalidate: 60 } 옵션으로 ISR도 설정 가능해요.
Q. 클라이언트 컴포넌트를 만들려면 어떻게 해야 하나요?
A. App Router 기본은 서버 컴포넌트인데요, 클라이언트 상태나 이벤트 핸들러가 필요하면 파일 최상단에 'use client' 지시자를 넣으면 돼요.
'use client';
import { useState } from 'react';
export default function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>Clicked {count} times</button>
);
}
이렇게 하면 클라이언트 전용 컴포넌트가 돼서, 상태 관리와 이벤트를 쓸 수 있어요.
Q. 레이아웃 분리하는 방식이 왜 달라졌나요?
A. App Router에서는 layout.js 파일로 계층적 레이아웃을 정의해요. 페이지 사이에서 중복되는 UI(헤더, 네비게이션 등)를 중복 제거하기 좋고, 레이아웃 간에 상태를 유지하는 것도 지원합니다.
예를 들면 이렇게 루트 레이아웃을 만들고 내부에 페이지를 넣는 방식이에요:
// app/layout.js
export default function RootLayout({ children }) {
return (
<html>
<body>
<header>My Header</header>
{children}
<footer>My Footer</footer>
</body>
</html>
);
}
Next.js 13 App Router 마이그레이션 후기 관련 정보
제가 마이그레이션 하면서 겪은 삽질들
가장 헤맸던 부분 중 하나가 use client 지시자를 어디에 붙여야 하는지 감이 안 잡혔던 거예요. 클라이언트 사이드 훅(useState, useEffect 등)을 서버 컴포넌트에서 쓰면 당연히 에러가 나니까요.
"error: React Hook "useState" is called in function "Page" which is a Server Component"
이럴 때는 해당 컴포넌트를 완전히 클라이언트 컴포넌트로 만들어야 하는데, 'use client'를 빼먹으면 해결이 안 되더라고요.
또 하나는 데이터 패칭 시 fetch 옵션 설정 잘못해서 캐시 문제로 데이터가 안 바뀌는 현상도 있었어요. 이 부분은 { next: { revalidate: 0 } } 같은 옵션을 잘 써줘야 했습니다.
심화: 이런 점도 미리 알면 좋습니다
App Router는 기본적으로 React 18의 서버 컴포넌트 개념을 채택해요. 그래서 컴포넌트 렌더링이 서버에서 일어나고, 클라이언트에는 최소한의 자바스크립트만 전달됩니다.
덕분에 초기 로딩 속도가 빨라지고 SEO에 유리하지만, 클라이언트 상태나 이벤트 처리가 필요한 UI는 반드시 'use client' 선언이 필요하다는 점 꼭 기억하세요.
또 Suspense와 React 18의 비동기 렌더링 기능 덕분에 로딩 UI를 훨씬 자연스럽게 처리할 수 있으니 활용해보시면 좋아요.
자주 물어보시는 것들
Q. 마이그레이션 시 CSS, 스타일링은 어떻게 대응해야 하나요?
A. 스타일링 자체는 크게 다르지 않아요. 다만 global.css를 app/globals.css로 옮기고 layout.js에서 import하는 식으로 관리합니다. CSS Modules도 동일하게 쓸 수 있지만, 파일 위치가 app 폴더 기준이라는 점만 주의하세요.
Q. Next.js 13에서 API 라우트는 어떻게 처리하나요?
A. 기존 pages/api 경로를 그대로 쓸 수 있어요. 하지만 app/api 폴더에서도 Route Handlers라는 새로운 방식을 쓸 수 있고, 파일 위치와 메서드에 따라 간단하게 API를 만들 수 있어요.
Q. 기존 패키지나 라이브러리가 App Router와 충돌할 수도 있나요?
A. 네, 일부 Next.js 플러그인이나 라우팅과 밀접한 라이브러리는 호환 문제를 겪을 수 있어요. 특히 pages 방식에 맞춘 라우터 헬퍼들은 작동하지 않을 수 있어서, 각 라이브러리의 최신 버전을 확인하고 App Router 지원 여부를 반드시 체크하세요.
Q. 마이그레이션하면서 테스트 코드는 어떻게 바꿔야 할까요?
A. 서버 컴포넌트 특성상 렌더링 환경이 조금 달라졌기 때문에 테스트 모킹 방법이나 렌더링 테스트 방식이 조금 달라질 수 있어요. 특히 서버 컴포넌트의 데이터 패칭을 mock 처리할 때 jest.mock이나 MSW(Mock Service Worker)를 활용하는 방식이 유용했습니다.
마지막으로, App Router 도입은 초기 학습 곡선이 있어서 부담스러울 수 있는데요, 차근차근 기존 pages 폴더 코드를 옮기면서 서버 컴포넌트와 클라이언트 컴포넌트 구분을 명확히 하고, 레이아웃 구조부터 잘 설계하는 게 핵심입니다.
저처럼 처음에 많이 헤맸던 부분들, 궁금했던 점들 위주로 정리한 이 글이 마이그레이션 하시는 분들께 조금이나마 도움이 되었으면 좋겠네요.
'언어 > JavaScript' 카테고리의 다른 글
| 2026년 Vite 마이그레이션 중 꼭 알아야 할 설정 변경점들 (0) | 2026.08.06 |
|---|---|
| TypeScript 제네릭 타입 추론, 2026년 바뀐 점까지 제가 겪은 경험 담았어요 (0) | 2026.08.04 |
| JavaScript 클로저, 저도 처음엔 헷갈렸던 실전 사례들 (0) | 2026.07.22 |
| React useMemo와 useCallback, 진짜 필요할 때만 쓰는 법 알려드려요 (0) | 2026.07.18 |
| React Query 도입하면서 알게 된 캐싱 함정과 체크리스트 (0) | 2026.07.06 |
