Next.js App Router 시작하기 – React 개발자를 위한 입문 가이드
React로 개발하다 보면 한 번쯤 Next.js를 고민하게 됩니다. SEO가 필요하거나, 초기 로딩 속도를 개선하고 싶거나, 풀스택으로 확장하고 싶을 때 Next.js는 자연스러운 선택입니다.
Next.js 13부터 도입된 App Router는 기존 Pages Router와 완전히 다른 방식입니다. React 개발자라면 익숙한 개념도 있지만, 새로 배워야 할 것도 있습니다. 이 글에서 핵심만 빠르게 정리해드립니다.
App Router vs Pages Router
Next.js에는 두 가지 라우팅 시스템이 있습니다.
| 구분 | Pages Router | App Router |
|---|---|---|
| 도입 시점 | Next.js 초기 | Next.js 13+ |
| 폴더 | pages/ |
app/ |
| 기본 컴포넌트 | Client Component | Server Component |
| 레이아웃 | _app.js, _document.js |
layout.js (중첩 가능) |
| 데이터 페칭 | getServerSideProps 등 |
async 컴포넌트에서 직접 fetch |
2024년 이후 새 프로젝트라면 App Router를 권장합니다. Pages Router도 계속 지원되지만, 새로운 기능은 App Router에 집중되고 있습니다.
프로젝트 생성
npx create-next-app@latest my-app
설치 중 몇 가지 질문이 나옵니다:
Would you like to use App Router? › Yes
Would you like to use TypeScript? › Yes (권장)
Would you like to use Tailwind CSS? › 선택
App Router를 선택하면 app/ 폴더가 생성됩니다.
파일 기반 라우팅 이해하기
App Router의 핵심은 폴더 구조가 곧 URL이라는 점입니다.
app/
├── page.js → /
├── about/
│ └── page.js → /about
├── blog/
│ ├── page.js → /blog
│ └── [slug]/
│ └── page.js → /blog/hello-world (동적 라우트)
특수 파일들
| 파일 | 역할 |
|---|---|
page.js |
해당 경로의 페이지 UI |
layout.js |
공통 레이아웃 (헤더, 푸터 등) |
loading.js |
로딩 중 표시할 UI |
error.js |
에러 발생 시 표시할 UI |
not-found.js |
404 페이지 |
첫 번째 페이지 만들기
app/page.js를 열어보세요:
export default function Home() {
return (
<main>
<h1>Hello, Next.js!</h1>
<p>App Router로 만든 첫 페이지입니다.</p>
</main>
);
}
npm run dev로 실행하면 http://localhost:3000에서 확인할 수 있습니다.
Server Component vs Client Component
이 부분이 React 개발자가 가장 헷갈리는 포인트입니다.
App Router에서 모든 컴포넌트는 기본적으로 Server Component입니다.
Server Component (기본값)
// app/posts/page.js
// 이건 서버에서 실행됩니다
async function getPosts() {
const res = await fetch('https://api.example.com/posts');
return res.json();
}
export default async function PostsPage() {
const posts = await getPosts(); // 서버에서 직접 fetch
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
Server Component의 장점:
– 번들 크기에 포함되지 않음
– 데이터베이스에 직접 접근 가능
– API 키 같은 민감한 정보를 안전하게 사용
Client Component
useState, useEffect, 이벤트 핸들러 등 브라우저 기능이 필요하면 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>
);
}
'use client'는 파일 최상단에 선언해야 합니다. 이 파일과 여기서 import하는 모든 모듈이 클라이언트 번들에 포함됩니다.
언제 무엇을 쓸까?
| 상황 | 선택 |
|---|---|
| 데이터 fetch만 하고 표시 | Server Component |
| useState, useEffect 필요 | Client Component |
| onClick 등 이벤트 핸들러 | Client Component |
| 브라우저 API 사용 (localStorage 등) | Client Component |
팁: Server Component 안에 Client Component를 넣을 수 있습니다. 반대는 불가능합니다.
Layout으로 공통 UI 만들기
layout.js는 여러 페이지에서 공유하는 UI를 정의합니다.
// app/layout.js (루트 레이아웃)
export default function RootLayout({ children }) {
return (
<html lang="ko">
<body>
<header>
<nav>사이트 네비게이션</nav>
</header>
<main>{children}</main>
<footer>© 2026</footer>
</body>
</html>
);
}
페이지를 이동해도 레이아웃은 다시 렌더링되지 않습니다. 상태도 유지됩니다.
중첩 레이아웃
app/
├── layout.js → 전체 레이아웃
├── blog/
│ ├── layout.js → 블로그 전용 레이아웃
│ └── page.js
/blog 페이지는 두 레이아웃이 모두 적용됩니다.
정리
| 개념 | 핵심 포인트 |
|---|---|
| App Router | app/ 폴더 사용, Next.js 13+ 권장 방식 |
| 파일 라우팅 | 폴더 구조 = URL, page.js가 실제 페이지 |
| Server Component | 기본값, 서버에서 렌더링, fetch 직접 가능 |
| Client Component | 'use client' 선언, useState/이벤트 필요 시 |
| Layout | layout.js로 공통 UI, 중첩 가능 |
React 개발자라면 App Router의 기본 개념은 금방 익힐 수 있습니다. 처음에는 Server/Client Component 구분이 어색할 수 있지만, 몇 번 써보면 자연스러워집니다.