The "use cache" Directive
Next.js 16 introduces "use cache" for fine-grained caching. With cacheComponents: true, data fetching is dynamic by default—you opt into caching explicitly.
Basic Usage
From data/queries/post-queries.ts:
import { cache } from 'react';
import { cacheTag } from 'next/cache';
export const getPublishedPosts = cache(async () => {
'use cache';
cacheTag('posts');
return await prisma.post.findMany({
where: { published: true },
});
});Cache Invalidation with revalidateTag + refresh
In Server Actions, use revalidateTag with a profile plus refresh() for immediate UI updates:
import { refresh, revalidateTag } from 'next/cache';
export async function createPost(formData: FormData) {
await prisma.post.create({ data });
revalidateTag('posts', 'max'); // Stale-while-revalidate for other users
refresh(); // Immediate refresh for the current user
}Why Both?
| Function | Purpose |
|----------|---------|
| revalidateTag(tag, 'max') | Marks cache as stale, background revalidation |
| refresh() | Forces client router re-render immediately |
The combination ensures the current user sees updates instantly while other users get stale-while-revalidate behavior.
Granular Tags
Tag individual items separately:
export const getPublishedPostBySlug = cache(async (slug: string) => {
'use cache';
cacheTag(`post-${slug}`);
return await prisma.post.findUnique({ where: { slug } });
});When updating a post, invalidate both its specific tag and the list tag.