Opt-in caching with "use cache", revalidateTag + refresh() for invalidation.
Next.js 16 introduces "use cache" for fine-grained caching. With cacheComponents: true, data fetching is dynamic by default—you opt into caching explicitly.
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 },
});
});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 })
| 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.
Tag individual items separately:
export const getPublishedPostBySlug = cache(async (slug: string) => {
'use cache';
cacheTag(`post-${slug}`);
returnWhen updating a post, invalidate both its specific tag and the list tag.