안녕하세요! 오늘은 Next.js 13에서 도입된 앱 라우터(App Router)에 대해 자세히 알아보겠습니다. 기존의 페이지 라우터와는 완전히 다른 접근 방식으로, 처음엔 조금 어려워 보일 수 있지만 한 번 익숙해지면 정말 강력한 도구가 될 거예요.


🚀 앱 라우터가 뭔가요?


Next.js 13부터 도입된 앱 라우터는 React Server Components를 기반으로 한 새로운 라우팅 시스템입니다. 기존의 pages 폴더 대신 app 폴더를 사용하며, 파일 시스템 기반의 라우팅을 더욱 직관적이고 강력하게 만들어줍니다.


가장 큰 변화는 서버 컴포넌트가 기본이라는 점이에요. 이제 별도의 설정 없이도 서버에서 렌더링되는 컴포넌트를 만들 수 있고, 필요한 경우에만 클라이언트 컴포넌트로 변환할 수 있습니다.


📁 폴더 구조의 혁신


앱 라우터에서는 폴더와 파일의 역할이 명확하게 구분됩니다:



  • page.tsx: 실제 페이지 컴포넌트

  • layout.tsx: 공통 레이아웃 (헤더, 네비게이션 등)

  • loading.tsx: 로딩 상태 UI

  • error.tsx: 에러 상태 UI

  • not-found.tsx: 404 페이지



예를 들어, /blog/post/123 경로를 만들고 싶다면:

app/blog/post/[id]/page.tsx 파일을 생성하면 됩니다. 정말 직관적이죠?


💡 실제 구현해보기


간단한 블로그 페이지를 만들어볼게요. 먼저 루트 레이아웃부터 시작합니다:

iPhone X beside MacBook

📸 Photo by Timothy Hales Bennett

🔗 Unsplash에서 보기 • ❤️ 1395 likes • 클릭하면 원본 이미지로 이동




typescript<br>// app/layout.tsx<br>export default function RootLayout({<br>children,<br>}: {<br>children: React.ReactNode<br>}) {<br>return (<br><html lang="ko"><br><body><br><nav><br><h1>내 블로그</h1><br></nav><br>{children}<br></body><br></html><br>)<br>}<br>


이제 메인 페이지를 만들어보죠:


typescript<br>// app/page.tsx<br>export default function HomePage() {<br>return (<br><div><br><h2>최근 포스트</h2><br><p>여기에 포스트 목록이 들어갑니다.</p><br></div><br>)<br>}<br>


🔄 데이터 페칭의 새로운 방법


앱 라우터에서는 서버 컴포넌트에서 직접 데이터를 fetch할 수 있습니다. 더 이상 getServerSidePropsgetStaticProps가 필요 없어요!


typescript<br>// app/posts/page.tsx<br>async function getPosts() {<br>const res = await fetch('https://api.example.com/posts')<br>return res.json()<br>}<br>export default async function PostsPage() {<br>const posts = await getPosts()<br>return (<br><div><br>{posts.map(post => (<br><article key={post.id}><br><h3>{post.title}</h3><br><p>{post.excerpt}</p><br></article><br>))}<br></div><br>)<br>}<br>


정말 깔끔하고 직관적이죠? async/await를 컴포넌트에서 바로 사용할 수 있어서 코드가 훨씬 읽기 쉬워졌습니다.

person using smartphone

📸 Photo by Christian Wiediger

🔗 Unsplash에서 보기 • ❤️ 215 likes • 클릭하면 원본 이미지로 이동




⚡ 로딩과 에러 처리


앱 라우터의 가장 멋진 기능 중 하나는 자동 로딩 및 에러 처리입니다. 각 라우트 폴더에 loading.tsxerror.tsx 파일을 만들면 자동으로 처리해줍니다:


typescript<br>// app/posts/loading.tsx<br>export default function Loading() {<br>return (<br><div><br><p>포스트를 불러오는 중...</p><br><div className="spinner"></div><br></div><br>)<br>}<br>


typescript<br>// app/posts/error.tsx<br>'use client'<br>export default function Error({<br>error,<br>reset,<br>}: {<br>error: Error<br>reset: () => void<br>}) {<br>return (<br><div><br><h2>문제가 발생했습니다!</h2><br><button onClick={() => reset()}>다시 시도</button><br></div><br>)<br>}<br>


🎯 동적 라우팅 마스터하기


동적 라우팅도 더욱 강력해졌습니다. 대괄호 폴더명을 사용해서 매개변수를 받을 수 있어요:



  • [id]: 단일 동적 세그먼트

  • [...slug]: 모든 하위 경로 캐치

  • [[...slug]]: 선택적 모든 하위 경로 캐치



실제 예시를 보면:


typescript<br>// app/blog/[category]/[slug]/page.tsx<br>export default function BlogPost({<br>params<br>}: {<br>params: { category: string; slug: string }<br>}) {<br>return (<br><div><br><h1>카테고리: {params.category}</h1><br><h2>포스트: {params.slug}</h2><br></div><br>)<br>}<br>


🔧 클라이언트 컴포넌트 활용하기


모든 컴포넌트가 서버 컴포넌트로 기본 설정되지만, 상호작용이 필요한 경우 'use client' 지시어를 사용해서 클라이언트 컴포넌트로 만들 수 있습니다:


typescript<br>// app/components/Counter.tsx<br>'use client'<br>import { useState } from 'react'<br>export default function Counter() {<br>const [count, setCount] = useState(0)<br>return (<br><div><br><p>카운트: {count}</p><br><button onClick={() => setCount(count + 1)}><br>증가<br></button><br></div><br>)<br>}<br>


📈 성능 최적화 팁


앱 라우터를 사용할 때 성능을 극대화하는 몇 가지 팁을 공유해드릴게요:



  • 서버 컴포넌트 우선 사용: 상호작용이 꼭 필요한 경우가 아니라면 서버 컴포넌트를 사용하세요

  • 적절한 캐싱 활용: fetch 요청에 캐시 옵션을 설정해서 성능을 향상시키세요

  • Suspense 경계 설정: 로딩 상태를 세밀하게 관리할 수 있습니다

  • 스트리밍 활용: 페이지의 일부분을 먼저 보여주고 나머지를 점진적으로 로드할 수 있어요



🚨 주의사항과 마이그레이션


기존 프로젝트에서 앱 라우터로 이전할 때 몇 가지 주의할 점이 있습니다:


점진적 이전이 가능합니다. pagesapp 폴더를 동시에 사용할 수 있어서, 천천히 옮겨갈 수 있어요. 하지만 같은 경로에 대해서는 app 라우터가 우선순위를 가집니다.


API 라우트도 app/api 폴더로 이동해야 하고, 일부 기능들은 아직 실험적 단계이므로 프로덕션 환경에서는 신중하게 판단하시길 바랍니다.

a bunch of blue wires connected to each other

📸 Photo by Scott Rodgerson

🔗 Unsplash에서 보기 • ❤️ 98 likes • 클릭하면 원본 이미지로 이동




앱 라우터는 Next.js의 미래이자 현재입니다. 처음에는 학습 곡선이 있을 수 있지만, 한번 익숙해지면 개발 경험이 훨씬 향상될 거예요. 여러분도 한번 도전해보시길 권합니다!