tags
Label the cached renders of a page, so revalidateTag() can purge every page that shows some data.
app/posts/page.tsx
export const revalidate = 3600;
export const tags = ['posts']; // await revalidateTag('posts') purges this pageReference
| Option | Type | Default | Description |
|---|---|---|---|
tags | readonly string[] | [] | Cache tags stored with every cached render of the page. getServerSideProps can add more per render by returning { props, tags }. |
Rules
- A tag is a non-empty string of at most 256 bytes (UTF-8), without control characters, and well-formed Unicode (no unpaired surrogate).
- Tags starting with
_gio:are reserved for the server's own per-path tag. - A render keeps at most 64 tags: the static ones first, then those
getServerSidePropsreturned. Duplicates are dropped. - An invalid tag, a
tagsvalue that is not an array, or a tag past the 64th is ignored with a warning (once per route and problem), such ascache tags ignored: export const tags: tags must not be empty. The page still renders and is still cached, with its valid tags.
Behavior
- Tags are stored only with a render the server caches: a page with
revalidatewhose render is shareable. On an uncached page they are not read at all. revalidateTag(tag)from server code, orPOST /_gio/revalidatewith{ "tags": [...] }, purges every cached entry carrying the tag - every query string and locale variant, from memory and disk, PPR shells included. The next request renders fresh.- Every cached page can also be purged by its path with
revalidatePath(), with no tag at all.
Examples
Tags from the data a render used
app/posts/[id]/page.tsx
import { notFound, type GetServerSideProps, type InferPageProps } from '@gio.js/core';
import { db, type Post } from '../../../lib/db.server.ts';
export const revalidate = 3600;
export const tags = ['posts'];
export const getServerSideProps: GetServerSideProps<{ post: Post }, '/posts/:id'> = async (ctx) => {
const post = await db.posts.find(ctx.params.id);
if (post === null) notFound();
return { props: { post }, tags: [`post:${post.id}`, `author:${post.authorId}`] };
};
export default function PostPage({ post }: InferPageProps<typeof getServerSideProps>) {
return <article><h1>{post.title}</h1><p>{post.body}</p></article>;
}Purge after a write
app/api/posts/[id]/route.ts
import { revalidateTag, type RouteHandler } from '@gio.js/core';
import { db } from '../../../../lib/db.server.ts';
export const PUT: RouteHandler<'/api/posts/:id'> = async (req) => {
const post = await db.posts.update(req.params.id, req.json());
await revalidateTag(`post:${post.id}`); // this post's page
await revalidateTag(`author:${post.authorId}`); // pages listing the author's posts
return post;
};Good to know
- Name tags after data, not pages (
post:42,author:ada): one write can then purge every page that showed it. revalidateTag()with an invalid tag rejects with aTypeError; an invalid tag a page declares is only a warning.- Purges reach the server instance whose worker runs them. With several instances, call
POST /_gio/revalidateon each. tagsis read frompage.tsxonly.
Related
- On-demand revalidation - the guide
revalidateTagandrevalidatePathrevalidategetServerSidePropsresults/_gioendpoints
Version history
| Version | Changes |
|---|---|
v0.1.0-beta.8 | Introduced. |