Skip to the solution
MediumFrontend9 min read

What is the difference between revalidateTag(), updateTag(), and refresh() in Next.js 16?

694 views

The problem

Question presented to candidate: "A user edits their profile and clicks Save. Separately, a CMS webhook tells us a blog post changed. And a notification badge in the header should update after the user marks something as read. Next.js 16 gives us revalidateTag, updateTag and refresh. Which one goes where, and why?"

What a strong answer should cover:

  • revalidateTag(tag, profile) marks tagged data stale; with "max" the next visitor gets the stale copy instantly while a background refresh runs (stale-while-revalidate). Works in Server Actions and Route Handlers, so it fits webhooks.
  • updateTag(tag) expires the data immediately so the next read waits for fresh data: read-your-own-writes. Server Actions only; it throws elsewhere.
  • refresh() invalidates no cache at all; it asks the client router to re-render the current page from a Server Action, so uncached parts update.
  • The one-argument revalidateTag(tag) is deprecated and a TypeScript error in 16; it behaves like { expire: 0 }.
  • From a webhook that needs the data gone now, revalidateTag(tag, { expire: 0 }) is the substitute for updateTag.

Clarifying questions expected:

  • "Does the person who made the change need to see it immediately?" β€” that is the updateTag case.
  • "Is the trigger a user action in our UI or an external system?" β€” a Route Handler cannot use updateTag or refresh.

Code / implementation expected: Yes β€” one Server Action per function and a webhook Route Handler.

  • nextjs
  • caching
  • server-actions
  • next-16

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

9 min read Β· 8 sections

Read the code

The three functions in Server Actions
"use server";
import { refresh, revalidateTag, updateTag } from "next/cache";

export async function saveWithUpdateTag() {
  updateTag("news");
}

export async function saveWithRevalidateTag() {
  revalidateTag("news", "max");
}

export async function saveWithRefresh() {
  refresh();
}
A tagged cached function
import { cacheLife, cacheTag } from "next/cache";

let generation = 0;

export async function getNews() {
  "use cache";
  cacheLife("max");
  cacheTag("news");
  await new Promise((r) => setTimeout(r, 1500)); // a slow CMS call
  generation += 1;
  return { generation, generatedAt: new Date().toISOString() };
}
Webhook Route Handler (revalidateTag only)
// app/api/cms-webhook/route.ts
import { revalidateTag } from "next/cache";

export async function POST(request: Request) {
  if (request.headers.get("x-webhook-secret") !== process.env.CMS_SECRET) {
    return new Response("unauthorized", { status: 401 });
  }
  const { postId } = (await request.json()) as { postId: string };
  revalidateTag(`post-${postId}`, "max"); // visitors keep getting the old copy while it refreshes
  revalidateTag("posts", { expire: 0 }); // lists must not show the old title even once
  return Response.json({ revalidated: true });
}

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 57 of 129 in Next.js

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All Next.js questions
Up nextMedium

What is hydration in Next.js and what causes a hydration error?

Continue