Skip to the solution
MediumSystem Design6 min read

What is on-demand revalidation in Next.js (revalidatePath / revalidateTag)?

586 views

The problem

Question presented to candidate: "An editor publishes a change in the CMS and wants it live within seconds, not after the next hourly regeneration. How do you do that in Next.js, and when would you use a tag instead of a path?"

What a strong answer should cover:

  • revalidatePath(path) marks the cached output of one route as stale.
  • revalidateTag(tag, profile) marks every cached fetch or 'use cache' entry with that tag as stale, across all routes that use it.
  • In Next.js 16 revalidateTag takes a second argument; with 'max' the next request is served stale while it refreshes, with { expire: 0 } it refetches immediately. The single-argument form is deprecated.
  • updateTag expires a tag immediately for read-your-own-writes, but only inside Server Actions.
  • Trigger them from a Server Action after a mutation, or from a Route Handler used as a webhook.

Clarifying questions expected:

  • "Is the change triggered by our own form or by an external system?" β€” Server Action versus webhook Route Handler.
  • "Must the editor see the change on the very next request?" β€” decides between max, expire: 0 and updateTag.

Code / implementation expected: Yes β€” tagging a fetch, a webhook that revalidates it, and a Server Action.

  • nextjs
  • revalidation
  • revalidatetag
  • caching

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

6 min read Β· 8 sections

Read the code

Tagging data, a webhook, and a Server Action
// lib/posts.ts
export async function getPosts() {
  return fetch("https://cms.example.com/posts", { next: { tags: ["posts"] } }).then((r) => r.json());
}

// app/api/cms-webhook/route.ts
import { revalidateTag } from "next/cache";
export async function POST(req: Request) {
  if (req.headers.get("x-secret") !== process.env.CMS_SECRET) return new Response("no", { status: 401 });
  revalidateTag("posts", "max"); // serve stale once, refresh in the background
  return Response.json({ ok: true });
}

// app/admin/actions.ts
"use server";
import { updateTag } from "next/cache";
export async function savePost(formData: FormData) {
  await db.post.update({ /* ... */ });
  updateTag("posts"); // the editor sees their own change immediately
}

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 65 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

How do you handle loading and error states for data fetching in Next.js?

Continue