After Writing, Revalidate the Cache
Mutations & Revalidation
Every Server Action that changes data should pair the write with a `revalidatePath` or `revalidateTag` call so subsequent reads see the new state.
What you'll learn
- Insert, update, and delete, then revalidate
- Pick path vs tag based on scope of change
- Avoid stale UIs caused by missing revalidation
The single most common bug with Server Actions is forgetting to revalidate. The write succeeds, but the page shows yesterday’s data until the cache TTL expires. The fix is mechanical: write, then revalidate.
Insert
'use server'
import { revalidatePath } from 'next/cache'
export async function createTodo(form: FormData) {
await db.todos.insert({ text: String(form.get('text') ?? '') })
revalidatePath('/todos')
} Update
'use server'
export async function toggleTodo(id: string) {
await db.todos.update(id, { done: true })
revalidatePath('/todos')
} Delete
'use server'
export async function deleteTodo(id: string) {
await db.todos.delete(id)
revalidatePath('/todos')
} Path vs Tag
revalidatePath('/todos') invalidates one route. Use it when a single page shows the
data. revalidateTag('todos') invalidates every fetch tagged 'todos' — use it when the
same data is shown in multiple places (a sidebar count, a feed, a dashboard).
import { revalidateTag } from 'next/cache'
await db.todos.update(id, { done: true })
revalidateTag('todos') When Both Make Sense
A blog post mutation might want both: revalidatePath('/blog/' + slug) for the detail
page and revalidateTag('posts') for the index and the home-page feed.