cacheTag labels a cached entry with one or more strings so you can invalidate it on demand. Tags pair with revalidateTag and updateTag to purge specific data after a mutation without touching the rest of the cache. They are the on-demand half of caching, while cacheLife handles time.
Like the directive itself, cacheTag needs Cache Components enabled.
// app/lib/posts.ts
import { cacheTag } from 'next/cache'
export async function getPosts() {
'use cache'
cacheTag('posts')
const res = await fetch('https://api.example.com/posts')
return res.json()
}The tag names the entry. Later, invalidating the posts tag purges every cached entry that declared it, while other tags keep their data. A single entry can carry several tags at once.
Invalidating a tag
Two functions consume the tags. Which one you call depends on whether the user should see the change immediately after saving.
// app/actions.ts
'use server'
import { updateTag } from 'next/cache'
export async function addPost() {
await db.posts.create({ title: 'New post' })
updateTag('posts')
}updateTag runs only in Server Functions and gives read-your-writes, so the next read returns fresh data immediately. It is the right choice after a form submission. A real action would authorize the caller and validate its input before writing, since a Server Function is a public endpoint.
For background refresh instead, use revalidateTag, which since Next.js 16 takes a cache profile as its second argument:
// app/actions.ts
'use server'
import { revalidateTag } from 'next/cache'
export async function refreshPosts() {
revalidateTag('posts', 'max')
}This marks the tag stale and serves current data while new data loads in the background. Choose updateTag when the person who made the change should see it immediately, and revalidateTag when a short delay is fine. See revalidateTag vs updateTag for the full decision.
Multiple tags and limits
You can pass several tags in one call, which is how one entry belongs to both a broad group and its own record.
// app/lib/products.ts
import { cacheTag } from 'next/cache'
export async function getProduct(id: string) {
'use cache'
cacheTag('products', `product-${id}`)
const res = await fetch(`https://api.example.com/products/${id}`)
return res.json()
}A single call accepts up to 128 tags, each up to 256 characters. Tags beyond those limits are dropped with a console warning. Tags are idempotent, so applying the same one twice has no extra effect, and you can build a tag from fetched data, such as cacheTag('bookings-data', data.id), so each record gets its own name.
Tagging a component
A tag can also name a component's output, not just a data function.
// app/components/bookings.tsx
import { cacheTag } from 'next/cache'
export async function Bookings({ type }: { type: string }) {
'use cache'
cacheTag('bookings-data')
const res = await fetch(`https://api.example.com/bookings?type=${type}`)
const bookings = await res.json()
return <ul>{bookings.map((b) => <li key={b.id}>{b.title}</li>)}</ul>
}Invalidating bookings-data purges the cached list for every type at once. Tagging works the same at any scope, whether it is a function, a component, or a file.
Tags vs paths
Tags and paths clear different scopes.
| Tags | Paths | |
|---|---|---|
| Scope | A logical group across routes | One route URL |
| Best when | The same data appears in many places | Only one page shows the data |
| API | revalidateTag or updateTag | revalidatePath |
Use tags when one piece of data powers several pages, and paths when only a single route changes.
Common mistakes
- Calling revalidateTag with only a tag, which is the deprecated single-argument form and now produces a TypeScript error.
- Reaching for updateTag in a Route Handler, where it is not available, instead of revalidateTag.
- Tagging every entry with one broad tag, so one invalidation purges far more than intended.
To invalidate by route instead of by tag, revalidate the path directly. For how long a tagged entry lives, see cacheLife explained.
Rune AI
Key Insights
- cacheTag labels cached entries with one or more tags.
- updateTag gives read-your-writes in Server Actions.
- revalidateTag takes a cache profile as its second argument.
- Tags are idempotent and limited to 128 per call.
- Tags scope invalidation so unrelated entries stay cached.
Frequently Asked Questions
How many tags can one cacheTag call add?
What is the difference between updateTag and revalidateTag?
Conclusion
cacheTag gives every cached entry a name you can invalidate later. Tag entries where they are cached, then call updateTag in Server Actions for instant updates or revalidateTag for background refresh.
More in this topic
`generateMetadata` Explained with Real Examples
What generateMetadata does, when it runs, and how to use it for real routes: awaited params, deduplicated data fetching, extending parent metadata, and returning a 404 from metadata.
Canonical URLs in Next.js: `metadataBase`, `alternates.canonical`, and Dynamic Pages
How canonical URLs work in the Next.js App Router: setting metadataBase once, writing alternates.canonical per route, handling dynamic segments, and what happens when the base URL is missing.
Open Graph and Twitter Card Metadata in Next.js
How to write Open Graph and Twitter card metadata in the Next.js App Router: the openGraph and twitter fields, automatic card defaults, article tags, and image merge rules.