Optimistic Updates and Cache Invalidation
Make mutations feel instant with optimistic UI, then keep server and client state consistent using React Query invalidation and Next.js revalidation tools.
Optimistic Updates and Cache Invalidation is a free Next.js 15 Fullstack Web Apps lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Next.js 15 Fullstack Web Apps learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
What Are Optimistic Updates
An optimistic update applies a mutation to the UI immediately, before the server confirms it. If the request fails, you roll back. This makes apps feel instant.
- Update local cache right away.
- Send the request.
- Reconcile or roll back on the response.
The Tradeoff
Optimism improves perceived speed but risks showing stale or wrong data briefly. Use it for high-confidence actions like likes, toggles, and list edits, not for risky financial operations.
React Query useMutation Basics
useMutation exposes lifecycle hooks: onMutate, onError, onSuccess, and onSettled. Optimistic logic lives in onMutate.
const mutation = useMutation({
mutationFn: updateTodo,
onMutate: async (newTodo) => { /* optimistic */ },
onError: (err, vars, context) => { /* rollback */ },
onSettled: () => { /* refetch */ },
});Snapshot Before Mutating
In onMutate, cancel in-flight queries, snapshot the current cache, then write the optimistic value. The snapshot enables rollback.
onMutate: async (newTodo) => {
await queryClient.cancelQueries({ queryKey: ['todos'] });
const previous = queryClient.getQueryData(['todos']);
queryClient.setQueryData(['todos'], (old) => [...old, newTodo]);
return { previous };
}Rolling Back on Error
If the mutation fails, restore the snapshot you returned from onMutate. The context argument carries it.
onError: (err, newTodo, context) => {
queryClient.setQueryData(['todos'], context.previous);
}Reconciling with the Server
In onSettled, invalidate the query so React Query refetches the authoritative server state, replacing your optimistic guess with real data.
onSettled: () => {
queryClient.invalidateQueries({ queryKey: ['todos'] });
}A Pure Optimistic Reducer
The merge logic is just data transformation. Here is the add-and-rollback idea in plain JS.
let todos = [{ id: 1, text: 'A' }];
const snapshot = [...todos];
todos = [...todos, { id: 2, text: 'B (optimistic)' }];
console.log('optimistic', todos.length);
todos = snapshot;
console.log('rolled back', todos.length);Server-Side: revalidatePath
When a Server Action mutates data, call revalidatePath to purge the Next.js cache for that route so the next render shows fresh data.
'use server';
import { revalidatePath } from 'next/cache';
export async function addTodo(text) {
await db.todo.create({ data: { text } });
revalidatePath('/todos');
}Tag-Based Invalidation
revalidateTag targets cached fetches tagged with a label, regardless of which path used them. Tag your fetches, then invalidate by tag.
await fetch('https://api.example.com/todos', {
next: { tags: ['todos'] },
});
// later, after a mutation:
import { revalidateTag } from 'next/cache';
revalidateTag('todos');useOptimistic in Server Actions
React 19 ships useOptimistic, which pairs naturally with Next.js Server Actions for built-in optimistic UI without a query library.
'use client';
import { useOptimistic } from 'react';
function List({ todos, addAction }) {
const [optimistic, addOptimistic] = useOptimistic(todos);
return <ul>{optimistic.map((t) => <li key={t.id}>{t.text}</li>)}</ul>;
}Choosing the Right Tool
Match the tool to the layer:
invalidateQueries— client cache (React Query).revalidatePath/revalidateTag— server data cache.useOptimistic— instant client feedback with Server Actions.
Quick Check
In a React Query optimistic update, what is the purpose of the value returned from onMutate?
Recap
You learned to keep state consistent during mutations:
- Apply optimistic updates in
onMutatewith a snapshot for rollback. - Roll back in
onError, reconcile inonSettled. - Use
revalidatePathandrevalidateTagfor server cache. - Reach for
useOptimisticwith Server Actions.
Frequently asked questions
Is the “Optimistic Updates and Cache Invalidation” lesson free?
Yes — the full text of “Optimistic Updates and Cache Invalidation” is free to read here on the web, and the Next.js 15 Fullstack Web Apps course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Next.js 15 Fullstack Web Apps course, upgrade to CoddyKit PRO.
What will I learn in “Optimistic Updates and Cache Invalidation”?
Make mutations feel instant with optimistic UI, then keep server and client state consistent using React Query invalidation and Next.js revalidation tools. You practise Next.js 15 Fullstack Web Apps with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Next.js 15 Fullstack Web Apps?
No prior experience is required. Next.js 15 Fullstack Web Apps on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Optimistic Updates and Cache Invalidation” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Next.js 15 Fullstack Web Apps lesson?
Yes. Every Next.js 15 Fullstack Web Apps lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- React Query for Server State
- Client-Side State with Zustand/Jotai
- Server-Side Caching Strategies
- Optimistic Updates and Cache Invalidation