Skip to main content

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:

javascript
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:

javascript
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.

javascript
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.

javascript
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".


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).

javascript
queryClient.invalidateQueries(['comments', postId]); queryClient.invalidateQueries(['posts']);

5. SWR: a similar mechanism

In SWR you can call:

javascript
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 list

SUMMARY

ReasonWhat happens without invalidation
Data doesn't update in the UIThe user sees stale information
Inconsistency between componentsDifferent parts show different versions of the data
Errors in dependent requestsLists and details drift apart
Bloated cacheMemory is wasted, data is out of date
Loss of user trust"I changed it, why didn't it update?"

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.