본문으로 건너뛰기
개발 머꼬
개발 노트Next.js
hohyeon.dev29

글을 쓰고 목록으로 갔는데 방금 쓴 글이 없던 이유

  • #Engineering Note
  • #Next.js

문제 발생

글 작성 Server Action에서 캐시를 무효화하고 목록으로 리다이렉트했는데, 방금 쓴 글이 목록에 없었습니다. 새로고침하면 나타났습니다.

"use server";
await db.post.create({ data });
revalidateTag("posts", "max");
redirect("/posts");

원인 분석

두 함수의 목적이 다릅니다. Next.js 문서는 updateTagread-your-own-writes 시나리오를 위해 설계된 함수로 소개합니다 — 사용자가 무언가를 만들면 UI가 낡은 데이터 대신 그 변경을 즉시 보여주는 상황입니다.

동작도 명시돼 있습니다 — updateTag는 해당 태그의 캐시 데이터를 즉시 만료시키며, 다음 요청은 캐시의 오래된 내용을 서빙하는 대신 새 데이터를 가져올 때까지 기다립니다.

revalidateTag는 다릅니다 — 문서의 비교표대로 profile="max"(권장)에서는 캐시된 데이터를 서빙하면서 백그라운드로 새 데이터를 가져옵니다(stale-while-revalidate). 그래서 리다이렉트 직후의 요청은 아직 낡은 목록을 받습니다.

사용 위치 제약도 있습니다 — updateTag는 Server Action 안에서만 호출할 수 있고, Route Handler나 Client Component에서는 쓸 수 없습니다. 그런 곳에서는 revalidateTag를 씁니다.

해결 방안

  1. 뮤테이션 직후 보여줘야 하는 것은 updateTag입니다.
"use server";
const post = await db.post.create({ data });
updateTag("posts");
updateTag(`post-${post.id}`);
redirect(`/posts/${post.slug}`);
  1. 태그를 먼저 붙여둡니다. fetchnext.tags 또는 use cache 안의 cacheTag로 지정한 태그만 무효화할 수 있습니다.

  2. 웹훅·외부 트리거는 revalidateTag입니다. Route Handler에서 updateTag를 부르면 오류가 납니다 — 문서가 그 오류 예시까지 보여줍니다.

  3. 목록과 상세를 함께 무효화합니다. 하나만 지우면 다른 화면이 낡은 채로 남습니다 — 문서 예제도 postspost-{id} 둘 다 호출합니다.

  4. 태그 이름 규칙을 정합니다. 256자 제한이 있고 대소문자를 구분합니다. posts, post-<id>처럼 규칙을 코드 한 곳에서 만들면 오타로 무효화가 조용히 실패하는 일이 없습니다.

  5. 캐시를 아예 쓰지 않는 선택도 유효합니다. 이 저장소처럼 요청마다 DB를 읽는 구성이면 이 고민 자체가 없습니다 — 캐시는 측정한 뒤 필요할 때 켭니다.

공식 문서

마지막 수정

좋아요북마크

댓글0

아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.