Revalidating Mutations

Revalidating and Redirecting After a Mutation

A mutation that leaves the page showing yesterday's data is half finished. Call one of the invalidation functions of Revalidating Tags — updateTag, revalidatePath, revalidateTag or refresh — and Next.js 10,514 re-renders the route and streams the new RSC payload back in the action's own response: no follow-up request, no router.refresh(). The notes page prints its render time, so recording every request the browser made while submitting proves it:

Output of 49
BEFORE   : rendered at 06:17:37.099
REQUESTS : ['POST /notes']
AFTER    : rendered at 06:17:38.898

Pick by what changed: revalidatePath when one route is affected and tagging is overkill, updateTag when the user must see their own write at once, revalidateTag when stale content is acceptable — it does not wait, so no re-render rides along — and refresh() when the view depends on state outside the cache. A cookie set in the action triggers the same re-render by itself.

To send the user elsewhere instead, call redirect from next/navigation:

Revalidate first, then redirect (app/notes/actions.js)JavaScript
export async function createAndOpen(formData) {
  const user = await currentUser();
  if (user?.role !== "editor") throw new Error("Forbidden");
  const note = addNote(String(formData.get("text")), user.id);
  revalidatePath("/notes");           // must come first: redirect throws
  redirect(`/notes/${note.id}`);      // nothing after this line runs
}

redirect throws a NEXT_REDIRECT control-flow exception, with two consequences. Anything after the call is dead code, so revalidation goes first; and a try/catch around it swallows the redirect into a silent failure, so keep it outside the try. The navigation is free — the same POST streams the destination's payload, and the browser reaches /notes/n7 without a second request — but a redirecting action never returns, so useActionState never sees a state from it. When you need both a message and a navigation, return the message and call router.push (Programmatic Navigation).

Finally, an action runs inside a request a user is waiting on, and actions dispatch one at a time, so a slow one blocks the next. Queue the email and the PDF for later, and keep the action to four steps: authorize, validate, write, invalidate.