GioJSdocs
On this page

revalidateTag

Purge every cached page that carries a cache tag, from server code, so the next request for each renders fresh.

ts
import { revalidateTag } from '@gio.js/core';

await revalidateTag('posts');

Reference

ParameterTypeDefaultDescription
tag (required)string-A tag pages declared with export const tags = ['posts'] or returned from getServerSideProps as { props, tags: ['post:42'] }.

Returns

A Promise<RevalidateResult>: { ok, purged, error? }, the same as revalidatePath. purged counts the cache entries removed - each query-string and locale variant of a page is one entry.

Behavior

  • Every cached page stored under the tag is dropped from memory and disk, PPR shells included, and the promise resolves once the server confirms it. The next request for each of those pages renders fresh.
  • A page is stored under the tags of the render that produced it: its export const tags plus the tags its getServerSideProps returned for that render.
  • Unconfirmed purges resolve { ok: false, purged: 0, error } after 5 seconds (or when the server connection drops) and log a warning - they never throw. At most 16 calls are in flight per worker; the rest wait their turn.

Tag rules

The same rules apply to the tags pages declare. revalidateTag() rejects with a TypeError for a tag that breaks one; a page's invalid tags are dropped with a warning (logged once per route and problem) instead of failing the render.

  • A non-empty string of at most 256 bytes (UTF-8).
  • No control characters and no unpaired UTF-16 surrogates.
  • Not starting with _gio: - that prefix is the server's own (it tags every page with its path, for revalidatePath).
  • A page keeps at most 64 tags; duplicates count once, and the rest are dropped with a warning.

Examples

Tag a list and its items

app/posts/[id]/page.tsx
import { notFound, type GetServerSideProps, type InferPageProps } from '@gio.js/core';

export const revalidate = 60;
export const tags = ['posts'];          // every render of this page

export const getServerSideProps = (async (ctx) => {
  const post = await db.posts.find(ctx.params.id);
  if (post === null) notFound();
  return { props: { post }, tags: [`post:${post.id}`] };   // this render only
}) satisfies GetServerSideProps<{ post: Post }, '/posts/:id'>;

export default function PostPage({ post }: InferPageProps<typeof getServerSideProps>) {
  return <article><h1>{post.title}</h1></article>;
}
app/api/posts/[id]/route.ts
import { notFound, revalidateTag, type GioRequest } from '@gio.js/core';

export async function PUT(req: GioRequest<'/api/posts/:id'>) {
  const { title } = req.json<{ title: string }>();
  const post = await db.posts.update(req.params.id, title);
  if (post === null) notFound();
  const result = await revalidateTag(`post:${post.id}`);
  return { post, purged: result.purged };
}

With /posts/1 cached, the PUT answers "purged": 1, and the next GET /posts/1 is a miss in X-Gio-Cache that shows the new title.

Purge a batch

ts
const results = await Promise.all(changedIds.map((id) => revalidateTag(`post:${id}`)));
const failed = results.filter((r) => !r.ok);

Good to know

  • Tags apply to cached pages only - pages with revalidate set. A personalized render (one that read cookies, or sent its own set-cookie) is never stored, so it carries no tags. renderPage() in tests shows the tags a render would be stored under in cacheTags.
  • One server instance. Other instances need POST /_gio/revalidate with { "tags": [...] } - see Caching.
  • Outside the server (gio export, unit tests) it resolves ok: false and warns once.

Version history

VersionChanges
v0.1.0-beta.8Introduced.