castle.log
BlogWorkHistory
GitHub

Spring Boot와 Next.js 캐시 정리

2026년 05월 21일  15일 전
Next.js
Spring
Cache
Spring Boot와 Next.js 캐시 정리

핵심 요약

  • Spring Boot는 주로 @Cacheable, @CacheEvict, @CachePut 같은 캐시 추상화를 통해 서비스 로직 결과를 캐시합니다.
  • Spring Boot에서 TTL(만료 시간), eviction 정책, 저장 위치는 보통 Redis, Caffeine 같은 캐시 구현체가 담당합니다.
  • Next.js는 Spring처럼 서비스 메서드 결과를 캐시하는 구조라기보다, 데이터 fetch 결과, 서버 렌더링 결과, 라우트 결과를 프레임워크 차원에서 캐시합니다.
  • Next.js의 시간 설정은 일반적인 캐시 TTL보다는 재검증(revalidation) 주기에 가깝습니다.
  • Spring Boot에서 Swagger로 캐시 초기화 API를 만들 수 있듯, Next.js도 Route Handler로 관리용 엔드포인트를 만들어 revalidatePath, revalidateTag로 캐시 무효화를 구현할 수 있습니다.

1. Spring Boot의 캐시

개념

Spring Boot는 보통 비즈니스 로직 결과를 캐시하는 데 사용합니다.

예를 들어, 같은 상품 조회 로직이 반복 호출될 때 매번 DB를 조회하지 않고 캐시에 저장된 값을 재사용할 수 있습니다.

대표 어노테이션

  • @Cacheable: 캐시에 값이 없으면 실행 후 저장, 있으면 캐시 반환
  • @CacheEvict: 캐시 제거
  • @CachePut: 메서드는 실행하고 결과를 캐시에 갱신

예시 코드

@Service
public class ProductService {

    @Cacheable(value = "products", key = "#id")
    public Product getProduct(Long id) {
        return productRepository.findById(id).orElseThrow();
    }

    @CacheEvict(value = "products", key = "#id")
    public void evictProduct(Long id) {
    }
}

특징

  • 서비스 메서드 중심으로 캐시를 적용합니다.
  • 캐시 로직을 비즈니스 코드와 비교적 분리해서 다룰 수 있습니다.
  • Redis, Caffeine, Ehcache 같은 구현체와 함께 자주 사용됩니다.

2. Spring Boot에서 시간 지정은 어떻게 하나?

Spring Boot는 캐시 기능을 제공하지만, TTL 자체를 Spring이 직접 관리하는 구조는 아닙니다.

즉, 아래 같은 느낌입니다.

  • Spring: 캐시 추상화 제공
  • Redis/Caffeine: 실제 저장, TTL, eviction 담당

예시 이미지로 이해하면

  • @Cacheable("products")
  • 실제 "products" 캐시에 몇 분 동안 저장할지는 Redis 또는 Caffeine 설정에서 결정

정리

즉, Spring Boot에서는 보통:

  • 캐시를 어디에 저장할지
  • 몇 초/몇 분 뒤 만료시킬지
  • 최대 몇 개까지 저장할지

이런 정책을 캐시 구현체 설정에서 잡습니다.


3. Next.js의 캐시

개념

Next.js는 Spring처럼 서비스 메서드 호출 결과를 캐시하는 느낌보다, 다음을 캐시합니다.

  • fetch()로 가져온 데이터 결과
  • 서버에서 렌더링된 페이지 결과
  • 라우트 이동에 필요한 일부 클라이언트 캐시

즉, 캐시의 중심이 서비스 함수가 아니라 페이지/데이터/렌더링 결과에 가깝습니다.

예시 코드

const data = await fetch("https://api.example.com/products", {
  next: { revalidate: 3600 },
});

이 코드는 3600초 단위로 재검증되도록 설정한 예시입니다.

특징

  • 데이터 fetch와 렌더링 결과를 프레임워크 차원에서 캐시합니다.
  • 페이지 단위, 데이터 단위로 캐시를 다루는 경우가 많습니다.
  • 전통적인 백엔드 캐시보다는 정적 생성 + 재검증 개념이 강합니다.

4. Next.js에서 시간 지정은 가능한가?

가능합니다.
다만 Spring의 TTL과 완전히 같은 느낌은 아니고, 재검증 주기에 가깝습니다.

예시

export const revalidate = 3600;

또는

const data = await fetch("https://api.example.com/products", {
  next: { revalidate: 3600 },
});

의미

  • 3600초 동안은 기존 캐시 결과를 사용
  • 그 이후에는 다시 검증해서 새 결과를 생성

즉, Next.js는 보통 **"만료되면 삭제"**보다
**"시간이 지나면 다시 만들어라"**에 더 가깝습니다.


5. 한번 서버에 올린 HTML은 계속 그대로인가?

항상 그렇지는 않습니다.

경우 1. 진짜 정적 파일

public/ 아래에 둔 파일은 일반적인 정적 파일입니다.

예:

  • public/test.html
  • public/logo.png

이런 파일은 보통 다시 배포해야 변경됩니다.

경우 2. Next.js가 생성한 페이지

이건 설정에 따라 달라집니다.

  • 완전한 static export라면 다시 빌드/배포해야 반영됩니다.
  • ISR 또는 revalidate를 쓰고 있으면, 재배포 없이도 다시 생성될 수 있습니다.

즉, Next.js에서 보이는 HTML이 전부 같은 성격은 아닙니다.


6. Spring Boot와 Next.js 캐시의 차이

항목Spring BootNext.js
캐시 대상서비스 메서드 결과fetch 결과, 렌더링 결과, 라우트 결과
중심 위치백엔드 서비스 로직프레임워크 렌더링/데이터 계층
시간 설정Redis/Caffeine 등 구현체 TTLrevalidate 기반 재검증
캐시 제거@CacheEvictrevalidatePath, revalidateTag
대표 사용 목적DB/API 호출 감소페이지 성능 최적화, 정적/동적 렌더링 최적화

7. Spring Boot의 Swagger 캐시 초기화 API처럼 Next.js도 가능한가?

가능합니다.

Spring Boot에서는 종종 Swagger에서 호출할 수 있도록 관리용 API를 열어 캐시를 초기화합니다.

예를 들어:

@RestController
@RequestMapping("/admin/cache")
public class CacheAdminController {

    @DeleteMapping("/products")
    public ResponseEntity<?> clearProductsCache() {
        return ResponseEntity.ok().build();
    }
}

Next.js도 비슷하게 Route Handler를 만들어 관리용 엔드포인트를 만들 수 있습니다.


8. Next.js에서 캐시 초기화 API 만들기

path 기준 무효화

// app/api/admin/cache/clear/route.ts
import { revalidatePath } from "next/cache";
import { NextRequest, NextResponse } from "next/server";

export async function POST(req: NextRequest) {
  const auth = req.headers.get("x-admin-secret");

  if (auth !== process.env.ADMIN_CACHE_SECRET) {
    return NextResponse.json({ message: "unauthorized" }, { status: 401 });
  }

  revalidatePath("/products");

  return NextResponse.json({
    ok: true,
    message: "/products cache marked for revalidation",
  });
}

tag 기준 무효화

// app/api/admin/cache/clear/route.ts
import { revalidateTag } from "next/cache";
import { NextRequest, NextResponse } from "next/server";

export async function POST(req: NextRequest) {
  const auth = req.headers.get("x-admin-secret");

  if (auth !== process.env.ADMIN_CACHE_SECRET) {
    return NextResponse.json({ message: "unauthorized" }, { status: 401 });
  }

  revalidateTag("products", "max");

  return NextResponse.json({
    ok: true,
    message: "products tag marked for revalidation",
  });
}

9. Spring의 @CacheEvict와 Next.js 대응

Spring

@CacheEvict(value = "products", allEntries = true)
public void clearProductsCache() {
}

Next.js

revalidateTag("products", "max");

또는 페이지 단위면:

revalidatePath("/products");

차이점

Spring의 @CacheEvict는 보통 캐시 엔트리를 제거하는 느낌이 강합니다.

반면 Next.js의 revalidatePath, revalidateTag
보통 다음 요청 시 다시 검증/생성 대상으로 표시하는 개념에 더 가깝습니다.

즉, 완전히 같은 동작은 아니지만, 운영 관점에서는 충분히 비슷한 역할을 합니다.


10. 실무적으로 어떻게 이해하면 좋은가?

Spring Boot가 더 잘 맞는 상황

  • 서비스 로직 결과를 캐시하고 싶을 때
  • DB 조회, 외부 API 응답을 백엔드 레벨에서 줄이고 싶을 때
  • Redis 같은 중앙 캐시 저장소를 운영하고 있을 때

Next.js가 더 잘 맞는 상황

  • 페이지 응답 속도를 높이고 싶을 때
  • 서버 렌더링 결과를 효율적으로 재사용하고 싶을 때
  • 정적 생성과 동적 생성 사이를 유연하게 운영하고 싶을 때

같이 쓰는 경우

실무에서는 둘 중 하나만 쓰는 것이 아니라, 같이 쓰는 경우도 많습니다.

예:

  • Spring Boot: DB 조회 결과를 Redis에 캐시
  • Next.js: 페이지 fetch 결과와 렌더링 결과를 재검증 기반으로 캐시

즉, 백엔드 캐시 + 프론트/SSR 캐시를 함께 가져가는 구조도 충분히 가능합니다.


11. 최종 정리

Spring Boot와 Next.js는 둘 다 캐시를 다루지만, 접근 방식이 다릅니다.

  • Spring Boot는 서비스 로직 결과 캐시
  • Next.js는 데이터/렌더링 결과 캐시

또한 시간 설정도 차이가 있습니다.

  • Spring Boot: 구현체가 TTL 관리
  • Next.js: revalidate 기반 재검증

그리고 캐시 초기화도 둘 다 가능합니다.

  • Spring Boot: @CacheEvict, 관리용 API
  • Next.js: Route Handler + revalidatePath, revalidateTag

즉, Next.js에 캐시가 없는 것이 아니라,
Spring과 캐시의 위치와 동작 방식이 다르다고 이해하는 것이 가장 정확합니다.

이전 게시글React Error Boundary 정리
다음 게시글Next.js 아키텍처 설명