카테고리 없음

Next.js Server Actions와 캐시 무효화 — revalidatePath와 revalidateTag를 함께 설계하기

Roslyn 2026. 10. 2. 09:00
반응형

Server Actions로 폼 제출과 데이터 변경 코드를 가까이 둘 수 있지만, 저장이 끝난 뒤 화면이 왜 갱신되지 않는지는 별도의 문제입니다. 서버 데이터, 전체 경로, 브라우저 라우터 캐시가 서로 다른 층에 있기 때문입니다.

이번 글에서는 액션을 도입하는 방법보다 액션 이후 어떤 캐시를 언제 무효화할지에 집중합니다. 문서 버전과 현재 App Router 동작은 발행 전에 다시 확인해야 합니다.

Server Action은 서버 함수이지만 권한 경계가 아닙니다

Server Action은 서버에서 실행되고 POST로 호출되지만, 호출된 함수 안에서 인증과 권한을 다시 확인해야 합니다. 화면에서 버튼을 숨겼다고 해서 사용자가 해당 액션을 호출할 수 없게 되는 것은 아닙니다.

저는 액션의 첫 부분에서 세 가지를 확인합니다. 현재 사용자, 대상 리소스, 변경 권한입니다. 실패하면 데이터 변경 전에 명확한 오류를 반환합니다.

  • 인증: 누가 요청했는지 서버에서 확인합니다.
  • 권한: 해당 리소스에 변경 권한이 있는지 확인합니다.
  • 입력: 직렬화 가능한 값과 도메인 규칙을 검증합니다.

revalidatePath와 revalidateTag의 범위를 구분합니다

revalidatePath는 특정 경로나 페이지의 캐시를 다시 만들도록 요청할 때 이해하기 쉽습니다. revalidateTag는 여러 화면이 같은 데이터 태그를 공유할 때 더 작은 단위로 무효화할 수 있습니다.

문제는 너무 넓게 무효화하면 비용이 커지고, 너무 좁게 무효화하면 화면이 오래된 데이터를 보여 준다는 점입니다. 어떤 데이터가 어떤 태그에 묶이는지 먼저 그려야 합니다.

상황선택 후보확인할 것

한 경로의 글 수정 revalidatePath 목록·상세 경로의 관계
여러 화면의 같은 목록 revalidateTag 태그를 공유하는 요청
즉시 UI 반영 액션 반환값·refresh 서버와 브라우저 상태

캐시 종류를 섞어 말하지 않습니다

Next.js에는 Data Cache, Full Route Cache, Router Cache처럼 서로 다른 캐시가 있습니다. ‘캐시를 지웠다’는 표현만으로는 무엇이 새로 계산되는지 알 수 없습니다. 저는 버그를 재현할 때 데이터 요청, 서버 렌더, 브라우저 이동을 따로 기록합니다.

특히 개발 환경의 HMR 캐시와 배포 환경의 캐시를 혼동하지 않습니다. 로컬에서 새로 보인다고 운영에서도 즉시 갱신된다고 단정할 수 없습니다.

  • Data Cache: 외부 데이터 요청의 결과가 저장되는 층입니다.
  • Full Route Cache: 서버가 만든 경로 결과와 관련된 층입니다.
  • Router Cache: 브라우저가 방문한 경로 세그먼트를 보관하는 층입니다.

실패와 리다이렉트도 하나의 흐름으로 테스트합니다

액션이 성공할 때만 테스트하면 캐시 설계의 절반만 확인한 셈입니다. 권한 없음, 유효성 실패, 데이터베이스 오류, 성공 후 리다이렉트, 새로고침까지 한 흐름으로 재현해야 합니다.

저는 각 시나리오에서 저장 전·저장 후 서버 데이터·화면 데이터가 무엇인지 표로 기록합니다. 표가 맞지 않는 지점이 무효화 범위나 클라이언트 상태의 문제입니다.

실험 결과를 운영 판단으로 바꾸는 순서

개발 문서에서 가장 재사용하기 어려운 문장은 ‘잘 됩니다’입니다. 어떤 버전과 데이터, 부하에서 잘 되었는지 모르면 독자는 자신의 환경에서 다시 확인할 수 없습니다. 저는 새로운 기능을 검토할 때 SDK·런타임·패키지·데이터베이스 버전을 먼저 고정하고, 기존 구현을 기준선으로 보관합니다. 변경 전후의 코드와 측정 명령도 함께 기록합니다.

측정값이 좋아도 운영에 바로 도입하지 않습니다. 오류 추적, 로그의 의미, 배포와 롤백, 팀이 이해할 수 있는지까지 확인합니다. 프리뷰나 변경 중인 문서는 정식 기능과 구분하고, 문서에 확인 날짜와 테스트 범위를 적습니다. 독자가 복사해 사용해도 위험하지 않도록 적용하지 말아야 하는 조건도 함께 적는 것이 기술 글의 중요한 부분입니다.

  • 버전 잠금: 실험한 SDK·런타임·패키지·브라우저 버전을 기록합니다.
  • 기준선: 변경 전 기능·성능·오류 결과를 같은 입력으로 보관합니다.
  • 경계 사례: 빈 값·중복·실패·큰 입력에서 결과를 확인합니다.
  • 배포 판단: 적용·보류·롤백 중 하나를 고르고 근거를 남깁니다.

다음 작업에서 다시 확인할 항목

한 번 적용한 방법이 언제나 같은 결과를 내는 것은 아닙니다. 사람과 서비스와 원고의 조건이 바뀌면 같은 원칙도 다른 판단을 요구합니다. 그래서 저는 글을 작성한 뒤 결론만 보관하지 않고, 결론이 성립한 조건과 다시 확인해야 할 조건을 함께 적습니다. 이 기록이 있으면 몇 달 뒤 글을 업데이트할 때 당시의 경험을 현재의 사실처럼 착각하지 않을 수 있습니다.

특히 버전·정책·가격·플랫폼 기능처럼 외부에서 바뀌는 내용은 조사한 날짜와 공식 문서의 주소를 남깁니다. 발행 시점에 문서가 달라졌다면 본문에 변경 사실을 표시하고, 직접 확인하지 못한 부분은 독자가 알 수 있도록 범위를 제한합니다. 경험을 공유하는 글도 다른 사람의 환경에 그대로 적용될 수 있으므로, 성공 사례보다 실패 조건을 함께 쓰는 편이 안전합니다.

마지막으로 이 글을 읽은 분이 바로 할 수 있는 행동은 하나로 줄입니다. 모든 항목을 한꺼번에 바꾸기보다 현재 상태를 기록하고, 작은 실험을 한 번 실행하고, 결과를 다시 적는 순서입니다. 그렇게 쌓인 기록이 다음 글의 소재가 되고, 처음의 판단을 더 정확하게 고쳐 쓰는 근거가 됩니다.

  • 범위 표시: 이 글의 결론이 적용되는 환경과 적용되지 않는 환경을 구분합니다.
  • 날짜 기록: 버전·정책·가격·문서를 확인한 날짜를 남깁니다.
  • 실패 조건: 어떤 상황에서는 이 방법을 쓰지 말아야 하는지 적습니다.
  • 작은 실행: 독자가 오늘 시도할 수 있는 가장 작은 행동을 고릅니다.
  • 후속 기록: 실행 결과와 다음에 바꿀 조건을 별도 메모로 남깁니다.

이 기록을 나중에 다시 읽을 때는 결과만 보지 않고 당시의 조건도 함께 확인합니다. 조건이 달라졌다면 결론을 그대로 복사하지 말고 현재의 입력과 제약을 다시 적습니다. 그 과정을 거쳐야 이 글이 단순한 경험담이 아니라 다음 판단을 돕는 작업 기록으로 남습니다.

마치며

Server Actions의 장점은 API 코드를 줄이는 데 있지만, 캐시 일관성까지 자동으로 해결해 주는 것은 아닙니다. 액션 하나를 골라 어떤 데이터 요청과 경로가 영향을 받는지 그리고 revalidate 범위가 어디까지인지 먼저 그려 보시기 바랍니다.

참고한 문서: Next.js Server Actions · Next.js Caching

반응형