Next.js SSR 페이지 풀 페이지 캐싱

2025. 9. 8. 12:57·Frontend Development
728x90

서론

이번 글에서는 아직 다루지 않은 SSR(Server-Side Rendering) 페이지의 풀 페이지 캐싱에 대해 이야기합니다.

SSR은 매 요청마다 서버에서 HTML을 생성하므로 항상 최신 데이터를 보장하지만, 그만큼 성능 부담이 큽니다.
그렇다면 SSR 페이지를 캐싱하면서도 신선함을 유지할 수 있는 방법은 무엇일까요?


SSR의 본질 (Next.js 15 기준)

SSR이 하는 일

  • 매 요청마다 서버에서 HTML 생성
  • 데이터는 요청 시점에 가져옴
  • SEO 친화적, 항상 최신 상태 반영

적합한 경우

  • 자주 변하는 데이터
  • 사용자별 맞춤형 페이지
  • 인증 필요 페이지

성능 문제가 발생하는 경우

  • 모든 요청이 DB/API 호출을 동반
  • 고트래픽 시 서버 부하 급증
  • TTFB(Time to First Byte) 지연

따라서 풀 페이지 캐싱은 필수적인 최적화 전략이 됩니다.


풀 페이지 캐싱이 필요한 경우

  1. 데이터 갱신 주기가 짧지만 실시간은 아님
    예: 상품 상세 페이지, 블로그 상세, 마케팅 페이지
  2. 비로그인 대량 트래픽
    로그인 상태가 필요 없는 페이지는 동일 캐시를 공유 가능
  3. 복잡한 백엔드 로직을 거치는 경우
  4. 글로벌 서비스
    CDN과 엣지 캐싱을 활용해 전 세계 어디서나 빠른 응답 제공

캐싱하면 안 되는 경우:
실시간 주식 시세, 관리자 대시보드처럼 매 요청마다 다른 데이터가 필요한 경우


SSR 캐싱 전략

1. CDN + Cache-Control 헤더

// app/product/[slug]/page.tsx
import { headers } from 'next/headers';
import { fetchProductBySlug } from '@/lib/data';

export const dynamic = 'force-dynamic';

export default async function ProductPage({ params }) {
  const { slug } = params;
  const product = await fetchProductBySlug(slug);

  const responseHeaders = headers();
  responseHeaders.set(
    'Cache-Control',
    'public, s-maxage=60, stale-while-revalidate=120'
  );

  return (
    <main>
      <h1>{product.title}</h1>
      <p>{product.description}</p>
      <p>Price: ${product.price}</p>
    </main>
  );
}
  • s-maxage=60: CDN에서 60초 동안 캐시 유지
  • stale-while-revalidate=120: 만료 후에도 최대 120초 동안은 오래된 버전을 즉시 제공하며 백그라운드에서 새로 갱신

👉 Vercel, Netlify 등 CDN 기반 배포 환경에서 가장 간단하고 효과적인 방법


2. Redis 등 외부 저장소 활용

  • 요청 URL을 키로 사용
  • 첫 요청 시 SSR 결과를 Redis에 저장
  • TTL(Time to Live) 설정으로 신선도 유지
  • 주로 커스텀 서버 환경에서 활용

3. Edge Middleware + 변형된 캐시 키

// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export const config = { matcher: ['/product/:path*'] };

export function middleware(request: NextRequest) {
  const geo = request.geo?.country || 'US';
  const url = request.nextUrl.clone();
  url.pathname = `/${geo.toLowerCase()}${url.pathname}`;

  return NextResponse.rewrite(url, {
    headers: {
      'Cache-Control': 'public, s-maxage=60, stale-while-revalidate=120',
    },
  });
}

👉 국가별, A/B 테스트, 언어별 변형된 페이지를 캐싱할 때 활용


4. ISR (Incremental Static Regeneration) 조합

// app/blog/[slug]/page.tsx
import { getPost } from '@/lib/posts';

export const revalidate = 60; // 60초마다 재생성

export default async function BlogPost({ params }) {
  const post = await getPost(params.slug);
  return (
    <article>
      <h1>{post.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: post.content }} />
    </article>
  );
}
  • 최초 요청 시 정적 페이지 제공
  • 만료 후 첫 요청에서 새 버전 재생성 (백그라운드에서 처리)

👉 빠른 응답 + 일정 수준의 신선도 유지 가능


디버깅 방법 (Vercel 기준)

  1. 헤더 확인

    curl -I https://your-domain.com/page
    • x-vercel-cache: HIT | MISS | STALE
  2. 지역별 테스트
    VPN 또는 Vercel CLI 사용

  3. 캐시 우회 요소 확인

    • 세션 쿠키, force-dynamic 등
  4. Analytics 활용

    • 캐시 적중률, TTFB, 지역별 지연 시간 확인 가능

Best Practice

  • no-store는 진짜 필요할 때만 사용
  • stale-while-revalidate 적극 활용
  • 불필요한 쿠키 제거
  • 캐시 주기는 실제 데이터 갱신 주기 기반으로 설정
  • 캐시 변형은 꼭 필요한 수준까지만 (geo, 언어 등)

결론

SSR 페이지를 캐싱한다는 것은 모순처럼 보일 수 있지만, 사실은 대규모 트래픽을 안정적으로 처리하기 위한 핵심 전략입니다.

  • Cache-Control 헤더
  • Redis 등 외부 캐시
  • Edge Middleware
  • ISR 조합

을 적절히 활용하면, 최신성과 성능을 모두 잡는 SSR 페이지를 구현할 수 있습니다.

728x90
저작자표시 비영리 변경금지 (새창열림)

'Frontend Development' 카테고리의 다른 글

React 리렌더링(Re-rendering): Trigger → Render → Commit  (0) 2025.10.03
실무에서 꼭 알아야 할 JWT 저장소 보안 패턴과 공격 탐지 방법  (0) 2025.09.13
useEffect에서 setInterval이 상태를 못 따라오는 이유 (stale closure)  (0) 2025.09.07
React Error Boundary: 왜 아직도 클래스일까?  (0) 2025.09.07
setTimeout vs Promise.then vs queueMicrotask  (0) 2025.09.05
'Frontend Development' 카테고리의 다른 글
  • React 리렌더링(Re-rendering): Trigger → Render → Commit
  • 실무에서 꼭 알아야 할 JWT 저장소 보안 패턴과 공격 탐지 방법
  • useEffect에서 setInterval이 상태를 못 따라오는 이유 (stale closure)
  • React Error Boundary: 왜 아직도 클래스일까?
Kun Woo Kim
Kun Woo Kim
안녕하세요, 김건우입니다! 웹과 앱 개발에 열정적인 전문가로, React, TypeScript, Next.js, Node.js, Express, Flutter 등을 활용한 프로젝트를 다룹니다. 제 블로그에서는 개발 여정, 기술 분석, 실용적 코딩 팁을 공유합니다. 창의적인 솔루션을 실제로 적용하는 과정의 통찰도 나눌 예정이니, 궁금한 점이나 상담은 언제든 환영합니다.
  • Kun Woo Kim
    WhiteMouseDev
    김건우
  • 깃허브
    포트폴리오
    velog
  • 전체
    오늘
    어제
  • 공지사항

    • [인사말] 이제 티스토리에서도 만나요! WhiteMouse⋯
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
    • 분류 전체보기 (133)
      • Frontend Development (62)
      • Backend Development (25)
      • Algorithm (33)
        • 백준 (11)
        • 프로그래머스 (17)
        • 알고리즘 (5)
      • Infra (1)
      • 자료구조 (3)
      • Language (6)
        • JavaScript (6)
  • 링크

    • Github
    • Portfolio
    • Velog
  • 인기 글

  • 태그

    tailwindcss
    frontend development
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
Kun Woo Kim
Next.js SSR 페이지 풀 페이지 캐싱
상단으로

티스토리툴바