revalidateTag (fetch-cache invalidation)

Server-side fetch(url, { next: { tags: ["demo"] } }) caches the upstream response and indexes it by tag. Clicking the button POSTs to a server action that calls revalidateTag("demo") — every entry tagged "demo" is dropped from FetchCache; the next page render re-fetches fresh from upstream.

Tip
<code>revalidateTag</code> returns the number of entries dropped. If you get <strong>0</strong> when the cache seemed active, check that the tag string in the <code>fetch</code> call and in <code>revalidateTag</code> match exactly — matching is case-sensitive. Invalidation does not cross worker processes: if the server restarted, the cache was already empty.

Output

Outer (live): 2026-09-06T04:05:56.180Z

Cached receivedAt: 2026-09-06T04:05:56.203Z

How to read this

  1. Refresh a few times: outer ticks live, cached receivedAt stays frozen (within the 60 s TTL).
  2. Click the button: action runs server-side, revalidateTag("demo") drops the cached entry and reports how many entries were removed.
  3. The action's loader rerun fetches fresh — the next receivedAt you see is the post-invalidation timestamp.
src/app/examples/revalidate-tag/page.tsxTSX
import { revalidateTag } from "@bext-stack/framework/cache";

export const dynamic = "force-dynamic";

export async function action({ request }: { request: Request }) {
  const removed = revalidateTag("demo"); // returns count dropped
  return { ok: true, removed };
}

export default async function Page({ actionData }: any) {
  // Cached upstream fetch — receivedAt stays frozen until the tag
  // is invalidated.
  const r = await fetch("https://demo.bext.dev/api/echo?key=revalidate-tag", {
    next: { revalidate: 60, tags: ["demo"] },
  });
  const data = await r.json();
  return (
    <div>
      <p>Outer (live): {new Date().toISOString()}</p>
      <p>Cached receivedAt: <strong>{data.receivedAt}</strong></p>
      <form method="post">
        <button type="submit">revalidateTag("demo")</button>
      </form>
      {actionData?.ok ? <p>Invalidated {actionData.removed} entries</p> : null}
    </div>
  );
}