글을 쓰고 목록으로 갔는데 방금 쓴 글이 없던 이유
문제 발생
글 작성 Server Action에서 캐시를 무효화하고 목록으로 리다이렉트했는데, 방금 쓴 글이 목록에 없었습니다. 새로고침하면 나타났습니다.
"use server";
await db.post.create({ data });
revalidateTag("posts", "max");
redirect("/posts");원인 분석
두 함수의 목적이 다릅니다. Next.js 문서는 updateTag를 read-your-own-writes 시나리오를 위해 설계된 함수로 소개합니다 — 사용자가 무언가를 만들면 UI가 낡은 데이터 대신 그 변경을 즉시 보여주는 상황입니다.
동작도 명시돼 있습니다 — updateTag는 해당 태그의 캐시 데이터를 즉시 만료시키며, 다음 요청은 캐시의 오래된 내용을 서빙하는 대신 새 데이터를 가져올 때까지 기다립니다.
revalidateTag는 다릅니다 — 문서의 비교표대로 profile="max"(권장)에서는 캐시된 데이터를 서빙하면서 백그라운드로 새 데이터를 가져옵니다(stale-while-revalidate). 그래서 리다이렉트 직후의 요청은 아직 낡은 목록을 받습니다.
사용 위치 제약도 있습니다 — updateTag는 Server Action 안에서만 호출할 수 있고, Route Handler나 Client Component에서는 쓸 수 없습니다. 그런 곳에서는 revalidateTag를 씁니다.
해결 방안
- 뮤테이션 직후 보여줘야 하는 것은
updateTag입니다.
"use server";
const post = await db.post.create({ data });
updateTag("posts");
updateTag(`post-${post.id}`);
redirect(`/posts/${post.slug}`);-
태그를 먼저 붙여둡니다.
fetch의next.tags또는use cache안의cacheTag로 지정한 태그만 무효화할 수 있습니다. -
웹훅·외부 트리거는
revalidateTag입니다. Route Handler에서updateTag를 부르면 오류가 납니다 — 문서가 그 오류 예시까지 보여줍니다. -
목록과 상세를 함께 무효화합니다. 하나만 지우면 다른 화면이 낡은 채로 남습니다 — 문서 예제도
posts와post-{id}둘 다 호출합니다. -
태그 이름 규칙을 정합니다. 256자 제한이 있고 대소문자를 구분합니다.
posts,post-<id>처럼 규칙을 코드 한 곳에서 만들면 오타로 무효화가 조용히 실패하는 일이 없습니다. -
캐시를 아예 쓰지 않는 선택도 유효합니다. 이 저장소처럼 요청마다 DB를 읽는 구성이면 이 고민 자체가 없습니다 — 캐시는 측정한 뒤 필요할 때 켭니다.
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.