Actions and forms
Mutate and revalidate
Write data once, invalidate the affected view, and redirect only after the mutation has completed successfully.
8 minute lesson
A successful mutation can leave cached or previously rendered data stale. The action should identify which view or cache entry is now invalid.
Perform authorization, validation, and the write first. Then call the revalidation API that matches your caching model, such as revalidatePath('/notes'), and optionally redirect to the new resource. Do not redirect from inside a catch block that accidentally treats the framework redirect as an error.
Invalidate only after the write commits. Doing it before a failed write can regenerate the old data and leave that stale result cached again. When several writes form one operation, use a transaction so the cache never advertises a half-finished state.
redirect() throws a framework control-flow signal and ends the action. Put it after the error-handling region. Also design for retries: a double click, network retry, or resubmitted browser request can invoke the action more than once. A unique constraint or idempotency key protects the data; a pending button alone does not.
'use server'
import { revalidatePath } from 'next/cache'
import { redirect } from 'next/navigation'
export async function createNote(formData: FormData) {
const note = await saveValidatedNote(formData)
revalidatePath('/notes')
redirect(`/notes/${note.slug}`)
}
Connect the action to persistence, revalidate the smallest relevant path or tag, and redirect to the created note. Simulate a failed write and a repeated request; neither should create a false success or duplicate record.
Lesson completed