Invalidate the right TanStack Query entries after a mutation

A successful save can make more than one cached query stale. Renaming a project affects its detail screen, a project list and possibly filtered list membership. Design query keys so those related entries can be selected deliberately.
For a synthetic workspace application, reserve separate branches for lists and details:
const projectKeys = {
lists: (workspaceId: string) =>
["projects", workspaceId, "list"] as const,
list: (workspaceId: string, filter: string) =>
["projects", workspaceId, "list", { filter }] as const,
detail: (workspaceId: string, id: string) =>
["projects", workspaceId, "detail", id] as const,
};
Every input that changes the returned data belongs in the key. The query-key documentation describes this requirement. A filter that stays outside the key can make two distinct requests share one cache entry.
After the server confirms the save, invalidate the relevant detail entry and the workspace's list branch:
await Promise.all([
queryClient.invalidateQueries({
queryKey: projectKeys.detail(workspaceId, project.id),
exact: true,
}),
queryClient.invalidateQueries({
queryKey: projectKeys.lists(workspaceId),
}),
]);
This excerpt assumes an existing QueryClient and a successful mutation result. TanStack's invalidation guide documents prefix matching and the exact option.
Mutation arrow reaching detail and matching list cache keys.
Check the entries that should stay fresh
Seed two workspaces, each with an "active" list. Rename a project in the first workspace. Inspect which queries become stale and which active screens refetch. The second workspace should remain untouched under this key layout.
Test a change that moves a project between filters, such as archiving it. Updating only the detail entry leaves the active list wrong. Invalidating all list filters for the affected workspace is often easier to maintain than manually reproducing each filter's membership rule.
Invalidation marks matching data stale; it does not promise that every inactive query immediately sends a request. A screen can therefore show its previous cached result while a later fetch runs. Define how loading and stale-data indicators should behave.
If the mutation response contains the complete authoritative record, setting its exact detail cache can avoid an extra fetch. Lists still need a deliberate update or invalidation. Do not assume the response contains fields it never returned.
This cache organization provides no server authorization boundary. Workspace access must still be checked by the API. Review the API's response and mutation behavior before treating a cache refresh as proof that the save persisted.