우당탕탕
Next.js 13 App Router 마이그레이션 직접 해보니 생각보다 이랬어요 본문
Next.js 13에서 새롭게 도입된 App Router로 마이그레이션하는 작업을 직접 해봤는데요, 생각보다 삽질도 많고 헷갈리는 부분이 꽤 있었어요. 그래서 이 글에서는 제가 실제로 겪은 모든 과정을 솔직하게 공유하려고 합니다.
App Router를 어떻게 적용해야 하는지, 기존 Pages Router와의 차이점, 자주 막히는 부분과 해결법까지 다루니 Next.js 13 마이그레이션 고민하시는 분들은 끝까지 읽어보시면 좋을 거예요.
제 개발 환경과 버전 정보 알려드려요
이번 마이그레이션은 Next.js 13.4.4 버전에서 진행했어요. React 18 환경이고, Typescript 5.0을 함께 사용했습니다. 기존에는 Pages Router를 쓰고 있었고, 이번에 App Router로 기본 구조 전환했네요.
기존 Pages Router에서 App Router 이렇게 바꿨어요
사실 이 부분이 가장 막막했는데, App Router는 루트 디렉토리에 app 폴더를 만들고, 그 안에서 페이지와 레이아웃을 분리해 관리하는 구조더라고요. 기존 pages 폴더랑 완전히 달라서 적응이 필요했어요.
// app 폴더 구조 예시
/app
/layout.tsx // 모든 페이지에 적용되는 레이아웃
/page.tsx // 루트 페이지
/about
/page.tsx // /about 페이지
/dashboard
/layout.tsx // dashboard 페이지 내부 레이아웃
/page.tsx // /dashboard 페이지
이렇게 layout과 page 파일을 분리해서 재사용성을 높인 게 핵심이에요. 그래서 중복되는 헤더, 푸터, 사이드바 같은 부분은 layout에서 관리하는 식이죠.
마이그레이션 하면서 제가 겪은 삽질 포인트
여기서 많이들 헷갈려하시는 게 바로 데이터 패칭 방식이었는데요. App Router에서는 React Server Component가 기본이에요. 그래서 기존에 getStaticProps나 getServerSideProps 대신에 그냥 async 함수 안에서 데이터를 받아와서 바로 쓸 수 있더라고요.
export default async function Page() {
const res = await fetch('https://api.example.com/data', { cache: 'no-store' });
const data = await res.json();
return (
<main>
<h1>데이터 내용</h1>
<pre>{JSON.stringify(data, null, 2)}</pre>
</main>
);
}
이 부분에서 막혔던 게, 기본적으로 fetch는 캐시가 걸려 있어서 업데이트가 바로 안 되는 현상이었어요. 그래서 cache: 'no-store' 옵션을 꼭 넣어줘야 한다는 걸 알게 됐죠.
추가로 제가 쓴 팁과 조언
React Server Component라서 UI가 서버에서 렌더링되는데, 클라이언트 전용 이벤트를 쓰려면 'use client' 지시어를 꼭 맨 위에 적어줘야 해요. 이걸 깜빡하면 이벤트가 먹히지 않아서 애를 먹었어요.
// client component 예시
'use client';
import { useState } from 'react';
export default function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>클릭 {count} </button>
);
}
또한, 다음.js 13의 App Router는 파일명과 폴더 구조가 진짜 중요해서 이름 하나 잘못 붙이면 페이지가 아예 라우팅 안 됩니다. 특히 page.tsx와 layout.tsx 이름은 꼭 맞춰서 써야 한다는 점 기억하세요.
자주 받는 질문들
Q. 기존 getStaticProps 코드는 App Router에서 어떻게 대체하나요?
A. getStaticProps 대신 async 함수 안에서 fetch를 쓰고, 기본적으로 정적 생성이 필요하면 fetch에 cache: 'force-cache' 옵션을 넣어주면 돼요.
Q. 클라이언트 컴포넌트에선 useState, useEffect 꼭 써야 하나요?
A. 네, 클라이언트 상태나 라이프사이클 훅을 쓰려면 'use client' 지시어와 함께 useState, useEffect를 써야 해요. 서버 컴포넌트에선 쓸 수 없어요.
마이그레이션 자체가 큰 변화라 부담스러울 수 있는데, 구조를 잘 이해하고 나면 오히려 코드가 더 깔끔해지고 유지보수하기 편해지는 느낌이에요. 다른 Next.js 13 기능과도 자연스럽게 연동되고요. 이 글이 조금이나마 여러분의 프로젝트 전환에 도움이 되었으면 좋겠네요.
'언어 > JavaScript' 카테고리의 다른 글
| React useEffect 의존성 배열 때문에 고생하다가 알게 된 핵심 포인트 (0) | 2026.05.17 |
|---|---|
| JavaScript async await 쓰면서 제가 실수한 패턴 5가지와 해결법 (0) | 2026.05.13 |
| TypeScript 처음 도입하면서 헷갈렸던 부분들 정리!! (0) | 2026.05.11 |
| [Js] 뒤로가기 버튼에서 발생하는 캐시 BF캐시 (bfcache) (0) | 2022.09.19 |
| [Js] 따옴표(quotes)와 백틱(backtick)의 차이 (0) | 2022.09.08 |
