Next.js 16, Cache Component를 이해해보자

김현준·2026년 2월 28일

넥스트JS

목록 보기
8/8

Next.js 16에서 가장 크게 체감한 변화는 이것이다.

  • React Compiler
  • PPR (Partial Prerendering)
  • Cache Component의 정식 지원

그중에서도 직접 코드를 짜보면서 가장 인상 깊었던 건 Cache Component였다.

처음에는 이렇게 생각했다.

그냥 서버에서 하던 fetch를 컴포넌트 안으로 옮긴 거 아닌가?

결론부터 말하면
겉보기엔 맞지만, 실제로는 렌더링 방식 자체가 바뀐 것이다.


1️⃣ 기존 SSR 방식은 어떻게 동작했나

예를 들어 이런 페이지가 있다고 해보자.

const Home = async ({ searchParams }) => {
  const posts = await getPostList(await searchParams)

  return (
    <main>
      <PostList posts={posts} />
    </main>
  )
}

이 구조에서의 흐름은 이렇다.

  1. 사용자가 페이지 요청
  2. searchParams 기다림
  3. DB 조회 기다림
  4. 모든 데이터 준비 완료
  5. HTML 생성
  6. 브라우저로 전송

즉,

페이지 전체가 데이터 준비가 끝날 때까지 기다린다.

이게 전통적인 SSR이다.


2️⃣ Cache Component 구조는 무엇이 다르나

이제 구조를 이렇게 바꿔보자.

const Home = async ({ searchParams }) => {
  return (
    <main>
      <Suspense>
        <PostList searchParams={searchParams} />
      </Suspense>
    </main>
  )
}

그리고 실제 데이터 fetch는 여기서 한다.

export const PostList = async ({ searchParams }) => {
  const posts = await getPostList(await searchParams)

  return (
    <section>
      {posts.map(post => <PostCard key={post.id} />)}
    </section>
  )
}

겉보기에는
“fetch 위치만 바뀐 것”처럼 보인다.

하지만 실제로는 다르다.

이제 흐름은 이렇게 된다.

  1. 사용자가 페이지 요청
  2. 페이지 shell HTML 즉시 전송
  3. Suspense fallback 표시
  4. PostList 데이터 준비되면 해당 부분만 스트리밍
  5. 화면 일부 교체

즉,

전체 블로킹이 아니라, 컴포넌트 단위 블로킹이 된다.

이게 가장 큰 변화다.


3️⃣ 기본은 왜 “동적”이라고 하는가

Next 16의 기본 철학은 이렇다.

모든 것은 요청 기준으로 실행된다.

즉,

  • 요청마다 코드가 실행되고
  • searchParams, cookies를 자유롭게 사용할 수 있다
  • HTML은 매 요청마다 새로 생성된다

예전에는 Next가 자동으로 static인지 dynamic인지 추측했다.

이제는 추측하지 않는다.

기본은 dynamic
static으로 쓰고 싶으면 직접 표시해라

그 표시가 'use cache'다.


4️⃣ 'use cache'는 정확히 무엇을 하는가

use cache는 두 가지 방식으로 사용할 수 있다.


(1) 함수에 붙이면 → 데이터 캐싱

export const getPostList = async (params) => {
  'use cache'
  return db.query(...)
}

이 경우 캐싱되는 것은

함수의 반환값

이다.

  • DB를 다시 치지 않는다
  • API를 다시 호출하지 않는다
  • 계산을 다시 하지 않는다

하지만 컴포넌트는 여전히 렌더링된다.

이 방식은 이런 데이터에 적합하다.

  • 게시글 목록
  • 카테고리 목록
  • 설정값
  • 서비스 이름
  • searchParams 기반 데이터

입력이 같으면 결과도 같아야 한다는 조건만 만족하면 된다.


(2) 컴포넌트에 붙이면 → HTML 캐싱

export const CategoryNav = async () => {
  'use cache'
  const categories = await getCategoryList()

  return <nav>...</nav>
}

이 경우는 다르다.

렌더링 결과 HTML까지 저장된다.

즉,

  • 함수 실행 안 함
  • 렌더링 안 함
  • HTML 그대로 재사용

하지만 제약이 있다.

  • searchParams 사용 불가
  • cookies 사용 불가
  • headers 사용 불가

왜냐하면 요청마다 달라질 수 있기 때문이다.

컴포넌트 캐싱은

요청과 완전히 무관한 순수 UI

일 때만 안전하다.


5️⃣ 그래서 결국 무엇이 바뀌었는가

겉보기에는 fetch 위치가 바뀐 것처럼 보이지만
실제로는 이것이 바뀌었다.

이전지금
페이지 단위 블로킹컴포넌트 단위 블로킹
전체 HTML 대기부분 스트리밍
자동 static 최적화명시적 캐싱 선언

Next 16은 이렇게 말하는 것과 같다.

기본은 동적이다.
정적인 경계는 네가 직접 선언해라.

그리고 그 경계는 컴포넌트 단위다.


6️⃣ 한 문장으로 정리

Next.js 16의 Cache Component는

“데이터 대기와 캐싱의 기준을 페이지에서 컴포넌트로 내린 구조”

이다.

겉으로 보면 단순한 리팩토링처럼 보이지만,
실제로는 렌더링 패러다임이 바뀐 것이다.

참고자료

profile
기록하자

0개의 댓글