Post

Next.js에서 bfcache(Back-Forward Cache) 문제 해결하기

Next.js에서 bfcache(Back-Forward Cache) 문제 해결하기

bfcache(Back-Forward Cache)는 사용자가 브라우저의 “뒤로 가기” 또는 “앞으로 가기” 버튼을 눌렀을 때, 페이지를 다시 로드하지 않고 이전 상태 그대로 복원하는 브라우저 기능이다. 하지만 Next.js의 기본 캐싱 전략은 이 기능과 충돌하여, 페이지를 다시 불러오는 문제가 발생할 수 있다.

이번 글에서는 Next.js에서 bfcache 문제를 해결하는 방법을 정리한다.


1. 문제 원인

Next.js는 기본적으로 서버 사이드 렌더링(SSR)과 동적 페이지 생성을 활용하며, 이러한 방식은 Cache-Control: no-store와 같은 캐싱 설정을 사용해 항상 최신 데이터를 제공하도록 한다. 하지만 이 설정은 브라우저가 페이지를 완전히 다시 로드하도록 강제하며, bfcache가 활성화되지 않는 원인이 된다.

bfcache가 활성화되지 않으면:

  • 뒤로 가기/앞으로 가기를 눌렀을 때 페이지가 다시 로드됨
  • 사용자 경험(UX)이 저하됨
  • 불필요한 네트워크 요청이 발생하여 성능이 저하됨

2. 해결 방법

1. Middleware에서 Cache-Control 헤더 설정

Next.js의 Middleware를 활용하여 Cache-Control 헤더를 변경하면 bfcache가 활성화될 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// src/middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";

export function middleware(request: NextRequest) {
  const response = NextResponse.next();

  // bfcache를 위한 Cache-Control 헤더 설정
  response.headers.set("Cache-Control", "public, max-age=0, must-revalidate");

  return response;
}

// API 및 정적 파일을 제외한 모든 경로에 적용
export const config = {
  matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"]
};

💡 왜 Cache-Control: public, max-age=0, must-revalidate를 사용해야 할까?

  • public: 브라우저와 중간 캐시(프록시)에서 캐싱할 수 있도록 허용한다.
  • max-age=0: 캐시된 데이터를 바로 만료시키지만, 재검증 후 사용할 수 있다.
  • must-revalidate: 브라우저가 캐시된 데이터를 사용하기 전에 서버에 유효성을 확인하도록 한다.

이 설정을 적용하면 브라우저는 bfcache를 활성화하면서도 필요할 때만 데이터를 갱신하게 된다.


2. layout.tsx에서 메타데이터 설정

metadata를 수정하여 페이지의 메타 정보에 캐싱 설정을 추가한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
// src/app/layout.tsx
export const metadata = {
  metadataBase: new URL("https://your-site.com"),
  title: {
    default: "Your Site",
    template: "%s | Your Site"
  },
  description: "당신의 사이트 설명",
  // Cache-Control 설정 추가
  other: {
    "Cache-Control": "public, max-age=0, must-revalidate"
  }
};

💡 layout.tsx에서 캐싱 설정을 추가하는 이유

  • metadataBase는 정적 리소스 및 Open Graph(OG) 메타 태그의 기본 URL을 설정한다.
  • Cache-Control을 추가하면 페이지가 서버에서 응답할 때 캐싱 정책을 포함할 수 있다.
  • must-revalidate를 적용하여, 브라우저가 캐시된 페이지를 사용할지 여부를 결정할 수 있도록 한다.

3. 적용 후 기대 효과

이 설정을 적용하면: ✅ bfcache가 정상적으로 작동하여 뒤로 가기/앞으로 가기 시 페이지가 즉시 로드됨

불필요한 네트워크 요청이 줄어들어 성능이 개선

Next.js의 동적 페이지도 최신 데이터를 유지하면서도 UX가 향상


4. 추가적인 고려사항

  1. API 경로에는 적용하지 않기
    • API 응답은 최신 데이터를 유지해야 하므로 Cache-Control: no-store를 유지해야 한다.
    • API 라우트에서는 개별적으로 revalidate 값을 설정하여 캐싱을 관리해야 한다.
  2. 정적 페이지와 동적 페이지 분리
    • ISR(Incremental Static Regeneration)을 사용하는 페이지는 revalidate를 적절히 설정하여 bfcache를 방해하지 않도록 한다.
    • /blog, /docs 등 정적 페이지는 revalidate: 60과 같은 설정을 적용하면 좋다.
  3. 브라우저 지원 확인
    • 최신 크롬, 사파리, 파이어폭스에서는 bfcache가 활성화되지만, 일부 구형 브라우저에서는 동작 방식이 다를 수 있다.

5. 결론

Next.js에서 bfcache가 정상적으로 동작하지 않는 문제는 Cache-Control 설정을 조정하면 해결할 수 있다.

  • Middleware에서 Cache-Control: public, max-age=0, must-revalidate 설정
  • layout.tsx에서 metadata.other를 활용한 추가 설정

이렇게 설정하면 Next.js의 SSR 및 동적 데이터 관리와 함께 bfcache를 최적화하여 UX를 개선할 수 있다. 🚀

This post is licensed under CC BY 4.0 by the author.