Invalidations from Mutations

Purpose and Scope

Invalidations from mutations are the bridge between a write operation and the read queries that display the changed server state. A mutation changes something outside the cache, such as creating a todo, editing a record, or deleting an item. TanStack Query does not assume that every cached result can be patched safely from the mutation response. Instead, the documented workflow is to use mutation callbacks to mark related queries stale, then let active observers refetch in the background when appropriate. This page explains that workflow for React and Angular, and maps it to the shared QueryClient behavior that framework adapters call into.

Sources: docs/framework/react/guides/invalidations-from-mutations.md, docs/framework/react/guides/query-invalidation.md

The important distinction is that mutation success and query freshness are separate concerns. A successful mutation only tells the application that the write completed; it does not automatically identify every cached query that became outdated. Query keys provide that contract. If the application reads todos through keys that begin with the same top-level segment, the mutation can invalidate that family of queries without manually editing every cached page, filter, or view. The official guide frames this as a common follow-up step after successful writes, especially when related lists or detail views should reflect the new server state.

Sources: docs/framework/react/guides/invalidations-from-mutations.md, docs/framework/react/guides/query-invalidation.md

Relevant Source Files

  • docs/framework/react/guides/invalidations-from-mutations.md - Defines the React guide flow: create a mutation, handle success with the mutation callback, use the query client, and invalidate related keys such as todos and reminders.
  • docs/framework/react/guides/query-invalidation.md - Explains what invalidation does, how key matching works, and how prefix, exact, and predicate filters control which cached queries are marked stale.
  • docs/framework/angular/guides/invalidations-from-mutations.md - Mirrors the React invalidation guide for Angular, replacing hooks with experimental Angular injection APIs and a class-based component example.
  • packages/query-core/src/tests/queryClient.test.tsx - Provides the core test location for QueryClient behavior, which is the shared layer used by framework adapters when they call invalidation APIs.

Core Concepts

A query invalidation is not the same thing as assigning new data. When a query is invalidated, TanStack Query marks it stale, overriding any configured freshness window. If that query is currently rendered or otherwise actively observed through framework APIs, it can also be refetched in the background. This matters because many mutations affect more than one view. Adding a todo might change the main list, a filtered list, a project summary, and a reminder count. Targeted invalidation lets the cache ask the server for authoritative data again instead of duplicating server update rules in the client.

Sources: docs/framework/react/guides/query-invalidation.md

The mutation callback supplies the timing. In React, the guide uses the success callback on the mutation options object. That callback runs when the mutation function has completed successfully, so it is the natural place to invalidate queries that depend on the changed resource. The same concept appears in the Angular guide through the experimental injection function. The adapter-specific syntax changes, but the mental model does not: the mutation performs the write, the success callback chooses affected query keys, and the shared query client performs the cache operation.

Sources: docs/framework/react/guides/invalidations-from-mutations.md, docs/framework/angular/guides/invalidations-from-mutations.md

React Execution Flow

A typical React flow starts by getting the query client from context, then configuring a mutation. The mutation function sends the write request. The success callback calls the client invalidation method with a query filter. For one related resource, a single invalidation call is enough. For multiple resources, the guide shows batching with a promise collection so that the callback represents the whole follow-up operation. Returning or awaiting the invalidation promise is useful because the mutation remains pending until that asynchronous success work has completed, which can keep button states and progress indicators aligned with the cache refresh.

Sources: docs/framework/react/guides/invalidations-from-mutations.md

import { useMutation, useQueryClient } from '@tanstack/react-query'
 
const queryClient = useQueryClient()
 
const mutation = useMutation({
  mutationFn: addTodo,
  onSuccess: async () => {
    await Promise.all([
      queryClient.invalidateQueries({ queryKey: ['todos'] }),
      queryClient.invalidateQueries({ queryKey: ['reminders'] }),
    ])
  },
})

This example is intentionally key-driven. It does not search components, call refetch functions individually, or try to infer a schema relationship. The cache contract is the query key. Any query whose key matches the invalidation filter can be marked stale, and active matching queries can refetch. That makes invalidation scalable across route boundaries and component trees, because the mutation does not need to know which screens are mounted. It only needs to know which resource families have been affected by the write and how precisely those families are represented in query keys.

Sources: docs/framework/react/guides/invalidations-from-mutations.md, docs/framework/react/guides/query-invalidation.md

Query Matching and Precision

The matching behavior determines whether an invalidation is broad or narrow. Calling the invalidation method without a filter targets every query in the cache. Passing a key such as a todos prefix targets queries whose keys start with that prefix, including more specific keys that add pagination or filter variables. Passing a more specific key narrows the affected set to queries with the same structured variables. Adding exact matching narrows the operation further so only the exact key is selected. Predicate matching is the most flexible form, because it evaluates each cached query and returns a decision.

Sources: docs/framework/react/guides/query-invalidation.md

queryClient.invalidateQueries({ queryKey: ['todos'] })
 
queryClient.invalidateQueries({
  queryKey: ['todos', { type: 'done' }],
})
 
queryClient.invalidateQueries({
  queryKey: ['todos'],
  exact: true,
})
 
queryClient.invalidateQueries({
  predicate: (query) =>
    query.queryKey[0] === 'todos' && query.queryKey[1]?.version >= 10,
})

Use broad matching when a mutation affects a whole resource area, such as creating a new todo that may appear in several list variants. Use specific matching when a mutation affects only one view, such as updating a detail record with a known identifier. Use exact matching when a parent key represents a distinct resource that should not include child keys. Use predicates sparingly for cases where key structure alone is not expressive enough. The goal is to invalidate enough data to maintain correctness while avoiding unnecessary network work for unrelated queries.

Sources: docs/framework/react/guides/query-invalidation.md

Angular Adapter Flow

The Angular guide uses the same invalidation idea with experimental Angular Query APIs. A component injects the shared query client, defines a mutation through the injection function, and invalidates related query keys inside the success callback. The example shows todo and reminder keys, matching the React guide’s resource-oriented approach. The difference is ergonomic rather than architectural: React retrieves the client through a hook, while Angular uses dependency injection. Both adapters ultimately express the same sequence of successful write, callback execution, key-based invalidation, and optional background refetch for active queries.

Sources: docs/framework/angular/guides/invalidations-from-mutations.md

import { injectMutation, QueryClient } from '@tanstack/angular-query-experimental'
 
export class TodosComponent {
  queryClient = inject(QueryClient)
 
  mutation = injectMutation(() => ({
    mutationFn: addTodo,
    onSuccess: () => {
      this.queryClient.invalidateQueries({ queryKey: ['todos'] })
      this.queryClient.invalidateQueries({ queryKey: ['reminders'] })
    },
  }))
}

System-to-Code Mapping

The guides are adapter documentation, but the behavior is centered on the QueryClient. Framework packages expose native APIs that make the client available inside components, while the core package owns the cache operation being invoked. The React page teaches the useMutation and useQueryClient path. The Angular page teaches the injectMutation and injected QueryClient path. The query invalidation guide explains the shared semantics of marking matching queries stale and refetching active matches. The core QueryClient test file is the repository location that anchors these behaviors in the non-framework implementation layer.

Sources: docs/framework/react/guides/invalidations-from-mutations.md, docs/framework/angular/guides/invalidations-from-mutations.md, docs/framework/react/guides/query-invalidation.md, packages/query-core/src/tests/queryClient.test.tsx

Reader taskPublic API or conceptSource backing
Invalidate after a React mutation succeedsReact mutation success callback plus query client invalidationdocs/framework/react/guides/invalidations-from-mutations.md
Understand what invalidation changesMark matching queries stale and refetch active observersdocs/framework/react/guides/query-invalidation.md
Port the pattern to AngularExperimental Angular mutation injection and injected QueryClientdocs/framework/angular/guides/invalidations-from-mutations.md
Verify shared client behaviorQueryClient core testspackages/query-core/src/tests/queryClient.test.tsx

Practical Guidance and Edge Cases

Prefer invalidation when the mutation response is not enough to update every affected query with confidence. This is common for list membership, filtered results, computed counts, server-side sorting, permission-sensitive data, or any response that omits related resources. Atomic cache updates still have a place when the new value is fully known, but the query invalidation guide explicitly positions targeted invalidation and background refetching as the default alternative to maintaining a normalized cache by hand. That design keeps server rules on the server and lets the client remain declarative about which cached resources need fresh data.

Sources: docs/framework/react/guides/query-invalidation.md

Be deliberate about awaiting invalidations in mutation callbacks. In React, the guide notes that returning a promise from the success callback keeps the mutation pending until that work is fulfilled. This is valuable when the user interface should not consider the write workflow complete until related data has been marked stale and any triggered refetches have been scheduled or completed according to the client behavior. If the UI can move on immediately, a callback can still call invalidation without using the pending state as a synchronization point. Choose the behavior that matches the user experience.

Sources: docs/framework/react/guides/invalidations-from-mutations.md

A useful implementation checklist is to start from the read side. First, inventory the query keys used by the screens that should react to the mutation. Second, decide whether the write affects a resource family, a specific key, or a custom subset. Third, place invalidation in the mutation lifecycle callback that corresponds to the outcome you care about, usually success. Finally, test the visible behavior with mounted queries and with cached but inactive queries. Active matches can refetch in the background, while inactive stale queries will refresh when they are observed according to normal query behavior.

Sources: docs/framework/react/guides/invalidations-from-mutations.md, docs/framework/react/guides/query-invalidation.md

Next Steps

After implementing success invalidation, review query key design so resource prefixes and variables match the way your application needs to refresh data. Then read the broader query invalidation material for exact and predicate matching, and the mutations material for the rest of the mutation lifecycle callbacks. If you are using Angular, follow the experimental Angular guide’s injected client pattern and keep the same key strategy as the React examples. For deeper source-level confidence, use the QueryClient test suite as the place to inspect expected cache behavior around client operations.

Sources: docs/framework/react/guides/query-invalidation.md, docs/framework/angular/guides/invalidations-from-mutations.md, packages/query-core/src/tests/queryClient.test.tsx