IT기술· 7분 읽기
📘
Next.js 15 App Router 마스터 가이드 — Server Components 베스트 프랙티스
Next.js 15 App Router 완전 정복 가이드. 서버/클라이언트 경계, 데이터 페칭, 라우팅, 에러 핸들링, 최적화까지 베스트 프랙티스.
Next.js 15 App Router 마스터 가이드 — Server Components 베스트 프랙티스
Next.js 15의 App Router는 React Server Components를 중심으로 하는 새 패러다임입니다. 2026년 기준 프로덕션에서 검증된 베스트 프랙티스 정리.
1. 파일 시스템 구조
app/
layout.tsx # 루트 레이아웃 (필수)
page.tsx # 홈 /
loading.tsx # 로딩 UI
error.tsx # 에러 경계
not-found.tsx # 404
(marketing)/ # 라우트 그룹 (URL 영향 X)
page.tsx
blog/
[slug]/
page.tsx # /blog/xxx
api/
route.ts # REST 엔드포인트라우트 그룹 (group): URL에 영향 없이 레이아웃 공유용.
2. Server vs Client Components
기본은 서버. "use client" 명시해야 클라이언트.
tsx
// Server Component (default)
async function Page() {
const user = await fetchUser() // 서버에서 직접
return <ProfileCard user={user} />
}
// Client Component
"use client"
function InteractiveButton() {
const [count, setCount] = useState(0)
return <button onClick={() => setCount(count + 1)}>{count}</button>
}경계 원칙
- "use client"는 최하위 리프에 놓기
- 그 위는 서버 컴포넌트 유지
- props로 전달되는 값은 직렬화 가능해야 (JSON 가능한 타입만)
3. 데이터 페칭
tsx
// 병렬 페칭
async function Page({ params }) {
const [user, posts] = await Promise.all([
fetchUser(params.id),
fetchPosts(params.id),
])
return <Dashboard user={user} posts={posts} />
}fetch 자동 캐싱:
fetch(url)— 기본 캐시fetch(url, { cache: "no-store" })— 매 요청fetch(url, { next: { revalidate: 60 } })— 60초 ISR
4. Suspense + Streaming
tsx
import { Suspense } from "react"
export default function Page() {
return (
<>
<FastSection />
<Suspense fallback={<Skeleton />}>
<SlowSection />
</Suspense>
</>
)
}
async function SlowSection() {
await new Promise(r => setTimeout(r, 2000))
return <div>Done</div>
}느린 영역만 스트리밍. TTFB 즉시.
5. Server Actions
tsx
// app/actions.ts
"use server"
export async function createPost(formData: FormData) {
const title = formData.get("title") as string
await db.insert(posts).values({ title })
revalidatePath("/blog")
}
// app/blog/new/page.tsx
import { createPost } from "../actions"
export default function NewPost() {
return <form action={createPost}>...</form>
}REST API 별도 없이 서버 로직 직접 호출. CSRF 자동 보호.
6. Error Boundaries
tsx
// app/blog/error.tsx
"use client"
export default function Error({ error, reset }) {
return (
<div>
<p>{error.message}</p>
<button onClick={reset}>Retry</button>
</div>
)
}세그먼트 단위 에러 경계. 에러 나도 나머지 페이지는 정상.
7. Metadata & SEO
tsx
export const metadata = {
title: "My Page",
description: "...",
}
// 또는 동적
export async function generateMetadata({ params }) {
const post = await fetchPost(params.slug)
return { title: post.title }
}베스트 프랙티스 10가지
- 1서버 기본: "use client"는 꼭 필요할 때만
- 2데이터는 가능한 한 상위에서 페칭: props drilling 대신
- 3Suspense 적극 활용: 스트리밍으로 TTFB 극대화
- 4fetch + revalidate: Redis 없이 자동 캐시
- 5Server Actions: REST 대체, 보일러플레이트 감소
- 6dynamic = force-dynamic: 개인화 페이지 전용
- 7이미지 최적화:
필수 - 8폰트 최적화:
next/font사용 - 9
import server-only: 민감 코드 클라이언트 누수 방지 - 10Parallel Routes: 복잡 대시보드는
@slot활용
자주하는 실수
- 서버 컴포넌트에서
useState→ 에러 - Client 컴포넌트에서
fetch→ 성능 저하 (서버에서 페칭 권장) - Props로 함수/Date 전달 → 직렬화 에러
- "use client" 파일에서 async server component import → 혼란
마무리
App Router는 초기 학습 곡선이 있지만 한 번 익히면 SPA + SSR의 장점만 챙기는 개발 경험을 제공합니다. 2026년 새 Next.js 프로젝트는 무조건 App Router. Pages Router는 마이그레이션 대상.
🔧 이 글과 관련된 무료 도구
이 글과 관련된 상품 (NextJS15)[광고/제휴]
이 포스팅은 쿠팡 파트너스, 아마존 어소시에이트, 알리익스프레스 제휴 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다. 이는 상품 가격에 영향을 주지 않습니다.
As an Amazon Associate, Coupang Partner, and AliExpress affiliate, I earn from qualifying purchases at no extra cost to you.