Next.js 와 App Router
Next.js 와 App Router
Next.js 는 React 위에 서버 렌더링·라우팅·번들링을 묶은 프레임워크입니다.
1. Next.js 에 대한 이야기
Next.js 는 Vercel (당시 ZEIT) 의 Guillermo Rauch 팀이 만들었고 2016 년 10 월 25 일 첫 공개됐습니다. 라이선스는 MIT.
| 버전 | 시기 | 사건 |
|---|---|---|
| 1.0 | 2016 | SSR React 프레임워크로 등장. |
| 9 | 2019 | dynamic route · API routes. |
| 10 | 2020 | Image 컴포넌트 · Internationalized Routing. |
| 12 | 2021 | Rust 기반 SWC 컴파일러로 전환. Middleware. |
| 13 | 2022-10 | App Router + RSC 베타. Turbopack alpha. |
| 14 | 2023-10 | Server Actions stable. App Router 안정화. |
| 15 | 2024-10 | React 19 RC · Partial Prerendering 실험 · async request API. |
| 16 | 2025 | Cache Components (이전 PPR) 안정화 진행. |
App Router 는 13 에서 도입되어 14 에서 안정화됐고 15·16 의 기본 권장입니다. 이전의 Pages Router 도 여전히 동작합니다.
2. 파일 시스템 라우팅
App Router 는 app/ 디렉토리 안에서 폴더가 곧 경로입니다.
app/
layout.tsx // 루트 레이아웃
page.tsx // /
about/page.tsx // /about
blog/[slug]/page.tsx // /blog/:slug
(marketing)/ // 그룹 (URL 에 안 들어감)
pricing/page.tsx
특수 파일:
layout.tsx— 자식 라우트를 감쌉니다 (공유 UI).page.tsx— 라우트의 본문.loading.tsx— Suspense fallback.error.tsx— error boundary.not-found.tsx— 404 화면.route.ts— Route Handler (REST/JSON 엔드포인트).
3. React Server Components
App Router 의 컴포넌트는 기본이 서버 컴포넌트 (RSC) 입니다. 서버에서만 실행되고 JS 번들에 포함되지 않으며 DB · 파일시스템 · 비공개 API 키에 접근할 수 있습니다.
클라이언트에서 인터랙션이 필요하면 파일 상단에 "use client" 를 적습니다. 그 컴포넌트와 거기서 import 한 자식들이 클라이언트 번들에 포함됩니다.
// app/posts/page.tsx (서버 컴포넌트, 기본)
export default async function Page() {
const posts = await db.post.findMany()
return <PostList items={posts} />
}
// app/posts/LikeButton.tsx
"use client"
export function LikeButton() {
const [n, setN] = useState(0)
return <button onClick={() => setN(n+1)}>{n}</button>
}
이 경계가 App Router 의 핵심 사고방식입니다.
4. 렌더링 모드
| 모드 | 약자 | 시점 |
|---|---|---|
| Client-Side Rendering | CSR | 브라우저에서 렌더. SPA 의 기본. |
| Server-Side Rendering | SSR | 매 요청마다 서버에서 HTML 생성. |
| Static Site Generation | SSG | 빌드 타임에 HTML 생성. |
| Incremental Static Regeneration | ISR | SSG + 일정 주기 재생성. |
| Partial Prerendering / Cache Components | PPR | 한 페이지 안에서 정적+동적 부분 혼합. |
App Router 에서는 데이터 fetch 의 캐시 옵션이 곧 모드 선택이 됩니다.
fetch(url, { cache: "force-cache" }) // SSG 와 비슷
fetch(url, { cache: "no-store" }) // SSR
fetch(url, { next: { revalidate: 60 } }) // ISR (60초)
15·16 부터 cookies() · headers() 같은 동적 API 가 async 가 되어 명시적으로 await 해야 합니다.
5. App Router vs Pages Router
| 항목 | Pages Router | App Router |
|---|---|---|
| 디렉토리 | pages/ |
app/ |
| 라우트 단위 | 파일 1 개 = 라우트 | 폴더 + page.tsx |
| 데이터 | getServerSideProps · getStaticProps |
RSC 안에서 직접 await fetch() |
| Layout | _app.tsx 한 군데 |
폴더마다 layout.tsx 중첩 |
| 기본 컴포넌트 | 클라이언트 | 서버 |
신규 프로젝트에는 App Router 가 권장되지만 Pages Router 도 계속 지원됩니다.
6. 다른 프레임워크와의 비교
| 프레임워크 | 베이스 | 위치 |
|---|---|---|
| Next.js | React, Vercel | 가장 큰 React 메타프레임워크. |
| Remix | React, Shopify (2022 인수) | 표준 웹 플랫폼 (폼 액션) 강조. React Router 와 통합 (7+, 2024). |
| Astro | 자체 (2022 1.0) | content-first. 0-JS 기본, island hydration. |
| Nuxt | Vue | Next 의 Vue 판. |
| SvelteKit | Svelte | |
| TanStack Start | React | TanStack Router 기반 신규 메타프레임워크. |
선택은 트레이드오프입니다. SEO·서버 자원 접근·React 생태가 중요하면 Next 가 자주 거론되고, 콘텐츠 사이트는 Astro, 폼 중심 앱은 Remix/React Router 가 자주 거론됩니다.
7. 시작과 Server Action
pnpm dlx create-next-app@latest my-app
cd my-app
pnpm dev
// app/new/page.tsx
import { redirect } from "next/navigation"
async function create(formData: FormData) {
"use server"
const title = String(formData.get("title"))
await db.post.create({ data: { title } })
redirect("/")
}
export default function Page() {
return (
<form action={create}>
<input name="title" />
<button>저장</button>
</form>
)
}
8. Route Handler
// app/api/health/route.ts
export async function GET() {
return Response.json({ ok: true })
}
13 부터 dev 서버에서 Turbopack (Vercel · Rust) 이 점진 도입되어 15+ 에서 dev 의 기본입니다. 프로덕션 빌드도 Turbopack 으로의 전환이 진행 중이며 그 사이에는 webpack 이 함께 쓰입니다.
9. 자주 걸리는 자리
"use client" 의 전염성 — client 컴포넌트가 import 한 모든 컴포넌트는 자동으로 클라이언트로 분류됩니다. 가능하면 client 경계는 잎 (leaf) 에 두고 props 로 데이터를 받아 내려보냅니다.
서버에서만 쓰는 시크릿 — 환경변수 이름이 NEXT_PUBLIC_ 으로 시작하면 클라이언트 번들에 포함됩니다. 시크릿은 절대 NEXT_PUBLIC_ 접두사를 붙이지 않습니다.
fetch 캐시의 기본 — App Router 의 fetch 는 버전마다 기본 캐시 정책이 달라졌습니다. 15 부터는 기본이 캐시되지 않으며 명시적으로 cache 또는 revalidate 를 적습니다.
cookies() · headers() 호출 시점 — 이 API 를 부르면 라우트가 자동으로 동적이 됩니다. 정적 캐시를 원하던 페이지가 의도치 않게 동적이 되는 함정입니다.
React 19 와의 짝 — Next 15+ 는 React 19 와 짝이며 일부 라이브러리가 19 호환에 시간이 걸렸습니다. 락파일에서 react 버전이 일치하는지 확인합니다.
Image 컴포넌트의 sizes — 잘못 적으면 큰 이미지가 모바일에 내려갑니다. 반응형 이미지에서 자주 보이는 함정입니다.
하고픈 말
App Router 의 RSC 가 처음에는 부담이 큽니다. 하지만 한번 익숙해지면 클라이언트에 보낼 코드를 줄일 수 있고, DB · 시크릿을 서버에서 직접 다룰 수 있는 자유도가 생깁니다. "use client" 경계를 잎에 두는 흐름이 가장 안전합니다.
Next
- state-philosophy
- styling-tailwind
Next.js 공식 사이트 · Next.js GitHub · App Router 학습 · Rendering 문서 · Turbopack · Remix · Astro 를 참고합니다.