← Back
Edit Post
Title
Description
"use cache" with cacheTag, revalidateTag + refresh() for invalidation, granular tags.
Content
Markdown supported
# The "use cache" Directive Caching eliminates in-between states entirely—if content is pre-rendered, there's nothing to wait for. Next.js 16 introduces the `"use cache"` directive for fine-grained, explicit caching control. With `cacheComponents: true` in your Next.js config, **data fetching is dynamic by default**. This is the opposite of the previous implicit caching behavior. You now opt into caching explicitly with `"use cache"`. ## The Development Flow The recommended approach for this project: - **Fetching data** — Create queries in `data/queries/`, call in Server Components. Use React's `cache()` for request deduplication. - **Mutating data** — Create Server Functions in `data/actions/` with `"use server"`. Invalidate with `revalidateTag(tag, 'max')` + `refresh()`. - **Caching** — Add `"use cache"` to functions, components, or pages you want to cache across requests. ## Basic Usage Add the directive at the top of a function, then tag the cache for invalidation: ```tsx import { cacheTag } from 'next/cache'; import { cache } from 'react'; export const getPublishedPosts = cache(async () => { 'use cache'; cacheTag('posts'); return await prisma.post.findMany({ where: { published: true, archived: false }, orderBy: { createdAt: 'desc' }, }); }); ``` The `cache()` wrapper from React deduplicates calls within a single render. The `"use cache"` directive caches the result across requests. Together, they eliminate both redundant queries within a request and redundant work across requests. ## Cache Invalidation After mutations, you need to invalidate the cache and update the current user's view: ```tsx import { refresh, revalidateTag } from 'next/cache'; export async function createPost(formData: FormData) { 'use server'; await prisma.post.create({ data }); revalidateTag('posts', 'max'); // Mark stale, revalidate in background refresh(); // Force immediate re-render } ``` | Function | Purpose | |----------|---------| | `revalidateTag(tag, 'max')` | Marks cache stale, triggers background revalidation | | `updateTag(tag)` | Marks cache stale, revalidates immediately (blocking) | | `refresh()` | Forces immediate client re-render with fresh data | The `'max'` profile serves stale content while revalidating—other users get fast responses while fresh data generates. Use `updateTag` when you need the mutation to block until fresh data is ready. ## Granular Cache Tags Tag individual items for precise invalidation: ```tsx export const getPublishedPostBySlug = cache(async (slug: string) => { 'use cache'; cacheTag(`post-${slug}`); return await prisma.post.findUnique({ where: { slug, published: true }, }); }); ``` When updating a post: ```tsx revalidateTag('posts', 'max'); // Invalidate the list revalidateTag(`post-${slug}`, 'max'); // Invalidate this specific post refresh(); ``` This ensures both the post list and the individual post's detail page update. ## Push Dynamic Data Deep To maximize cacheable content, push dynamic data access as deep as possible in the component tree. Components that read `searchParams`, `cookies()`, or `headers()` become dynamic—wrap them in `<Suspense>` so static parent content can render immediately.
Published
Save Changes
Cancel