Suggest an editImprove this articleRefine the answer for “Cache invalidation”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**Invalidation (cache invalidation)** is the process of forcibly refreshing or removing stale data from the cache after the source data on the server has changed. **Key point:** if the cache isn't invalidated, it keeps treating the old data as current, and the UI lags behind reality.Shown above the full answer for quick recall.Answer (EN)Image## 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". --- ### 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). ```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 | 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?" |For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.