Next.js 15가 나온 뒤로 “App Router를 어떻게 써야 하는가"라는 질문을 주변에서 자주 받습니다. Pages Router에 익숙한 분들은 새로운 파일 구조와 Server Components 개념이 낯설고, 처음 Next.js를 배우는 분들은 어디서부터 시작해야 할지 막막하다고 합니다. 이 글에서는 Next.js 15의 핵심 개념을 실무 관점에서 정리하고, 실제로 풀스택 웹앱을 만들 때 어떻게 적용하는지 설명합니다.
Next.js 15는 React 19를 완전 지원하고, Turbopack이 기본 개발 서버로 활성화됩니다. 가장 크게 체감되는 변화는 fetch 캐싱 기본값입니다. 이전 버전에서는 fetch가 기본적으로 캐시되었지만, Next.js 15부터는 기본값이 no-store로 바뀌었습니다. 즉, 명시적으로 캐싱을 선언해야 합니다.
1
2
3
4
// Next.js 15: 명시적으로 캐시 설정 필요
constdata=awaitfetch('/api/posts',{next:{revalidate:3600}// 1시간 캐시
})
이 변화는 처음에는 불편하게 느껴질 수 있지만, 의도치 않은 stale 데이터 문제를 사전에 차단해주는 올바른 방향입니다.
App Router의 가장 중요한 개념이 Server Components입니다. app/ 디렉토리 안의 모든 컴포넌트는 기본적으로 Server Component입니다. Server Component는 서버에서만 실행되므로, 데이터베이스에 직접 접근하거나 환경 변수를 안전하게 사용할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// app/blog/page.tsx — Server Component (기본값)
import{db}from'@/lib/db'exportdefaultasyncfunctionBlogPage() {// 서버에서 직접 DB 쿼리 — 클라이언트에 노출 안 됨
constposts=awaitdb.post.findMany({orderBy:{createdAt:'desc'},take: 10,})return(<ul>{posts.map(post=>(<likey={post.id}>{post.title}</li>))}</ul>)}
반면 상태(state), 이벤트 핸들러, 브라우저 API가 필요하면 'use client' 지시어를 파일 상단에 추가해서 Client Component로 만듭니다.
1
2
3
4
5
6
7
8
9
10
11
12
'use client'// Client Component: useState, 이벤트 핸들러 사용 가능
import{useState}from'react'exportfunctionCounter() {const[count,setCount]=useState(0)return(<buttononClick={()=>setCount(c=>c+1)}>클릭:{count}</button>)}
실무에서 중요한 원칙이 있습니다. “가능한 한 Server Component로 유지하고, 반드시 필요한 경우에만 Client Component로 전환한다"는 것입니다. Client Component를 트리의 말단(leaf)에 배치할수록 번들 크기가 줄고 성능이 좋아집니다.
// 정적 데이터 (빌드 시 캐시)
constres=awaitfetch('https://api.example.com/posts',{cache:'force-cache'})// 주기적 재검증 (ISR)
constres=awaitfetch('https://api.example.com/posts',{next:{revalidate: 60}})// 항상 최신 데이터
constres=awaitfetch('https://api.example.com/posts',{cache:'no-store'})
2. ORM 직접 사용 (Server Component에서)
Prisma, Drizzle 같은 ORM을 Server Component에서 직접 호출하는 방식입니다. 중간에 API 레이어가 없어서 레이턴시가 줄어듭니다.
3. React Query / SWR (Client Component에서)
실시간 업데이트가 필요하거나 낙관적 UI 패턴을 구현할 때는 클라이언트 사이드 데이터 패칭 라이브러리를 사용합니다.
Next.js 15의 App Router는 처음에는 개념이 많아 보이지만, 핵심은 단순합니다. “데이터 패칭과 렌더링은 서버에서, 인터랙션은 클라이언트에서"라는 원칙을 따르면 됩니다. Server Components를 최대한 활용해서 클라이언트 번들을 줄이고, Route Handlers와 Server Actions로 API를 정리하면 기존 Pages Router 대비 훨씬 깔끔한 코드베이스를 만들 수 있습니다.
풀스택 웹앱을 빠르게 프로토타이핑해야 하는 상황이라면 Next.js 15 + Prisma + Vercel 조합을 강력히 추천합니다. 배포까지의 시간이 눈에 띄게 줄어들 것입니다.