Cache invalidation
What cache invalidation is
Invalidation (cache invalidation) is the process of forcibly refreshing or removing stale data from the cache after the source data (on the server or in the DB) has changed.
In other words, if the user or the application changed the data, the cache must stop treating it as current and fetch fresh data.
Why this is critical
1. So the user doesn't see stale data
Example:
await fetch('/api/user/1', { method: 'PATCH', body: { name: 'Alex' } });You changed the user's name on the server. If the cache (/api/user/1) isn't invalidated, the component keeps showing the old name: React will think "everything's fine, the data is already there".
The UI lags behind reality. The user sees old information, while the API has long since been updated.
2. To avoid logical errors
If other parts of the app use the same data (for example, a user list and a profile), then changing one of them can leave the whole app with inconsistent data.
The list shows "Alex", while the card shows "Alexander".
The reason: the cache wasn't invalidated after the PATCH request.
3. To avoid errors in chains of dependent data
Suppose:
- /api/projects -> the list of projects,
- /api/projects/:id -> the project's detail page.
After updating one project, you need to:
- update its detailed data;
- and invalidate the project list so it updates too.
If you don't do this, the list keeps the old version, even though the details have already been updated.
4. So "stale" caches don't pile up
If the cache is never invalidated:
- it grows uncontrollably;
- the data stops matching the server;
- the app gets "stuck" in an old state.
This is especially critical during long sessions (an SPA without a page reload).
How to invalidate the cache properly
1. Manual invalidation
After a successful POST, PATCH, PUT, or DELETE, you need to tell the library: "This data is stale, refresh it".
React Query:
import { useQueryClient } from "@tanstack/react-query";
const queryClient = useQueryClient();
async function updateUser(id, newData) {
await fetch(`/api/users/${id}`, { method: "PATCH", body: JSON.stringify(newData) });
// Invalidation
queryClient.invalidateQueries({ queryKey: ["user", id] });
queryClient.invalidateQueries({ queryKey: ["users"] }); // if the list depends on it
}React Query will itself send a repeat request to the server to get fresh data.
2. Optimistic update
Sometimes you can update the UI immediately, without waiting for the server's response.
queryClient.setQueryData(['user', id], old => ({ ...old, ...newData }));
await fetch(`/api/users/${id}`, { method: 'PATCH', body: JSON.stringify(newData) });
queryClient.invalidateQueries(['user', id]);The user sees an instant response, and React Query then quietly loads the current data in the background and syncs it.
3. Stale Time + Background Refetch
If data is cached for a limited time (staleTime), then once it expires, React Query considers it "stale" and automatically makes a repeat request when the window regains focus or the component remounts.
useQuery({
queryKey: ['user', id],
queryFn: fetchUser,
staleTime: 5 * 60 * 1000, // 5 minutes
});Even if you forget to invalidate manually, the data won't remain "forever stale".
4. Invalidating related data
If you have, for example:
- /api/posts
- /api/posts/:id/comments
and a user adds a new comment, you need to invalidate not just /comments, but also /posts (if it shows the comment count).
queryClient.invalidateQueries(['comments', postId]);
queryClient.invalidateQueries(['posts']);5. SWR: a similar mechanism
In SWR you can call:
import useSWR, { mutate } from 'swr';
await fetch('/api/user/1', { method: 'PATCH', body: JSON.stringify(data) });
// Invalidation
mutate('/api/user/1'); // refetch
mutate('/api/users'); // if there's a dependent listSUMMARY
| Reason | What happens without invalidation |
|---|---|
| Data doesn't update in the UI | The user sees stale information |
| Inconsistency between components | Different parts show different versions of the data |
| Errors in dependent requests | Lists and details drift apart |
| Bloated cache | Memory is wasted, data is out of date |
| Loss of user trust | "I changed it, why didn't it update?" |
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.