# Tanstack Query Intent Compositions Automatic Invalidati A8e9b778

> Use this when designing automatic invalidation policies for TanStack Query mutations with MutationCache callbacks, mutationKey-to-queryKey matching, mutation meta invalidation tags, awaited invalidation, and exclusions for static or unrelated queries.

- Skill: `lukasa1993/tanstack-query-intent-compositions-automatic-invalidati-a8e9` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add lukasa1993/tanstack-query-intent-compositions-automatic-invalidati-a8e9`
- Raw SKILL.md: https://api.skillmd.com/api/skills/lukasa1993/tanstack-query-intent-compositions-automatic-invalidati-a8e9/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- License: MIT
- Author: lukasa1993 (https://skillmd.com/u/lukasa1993)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/lukasa1993/tanstack-query-intent-compositions-automatic-invalidati-a8e9

---


## Core Patterns

Use local mutation callbacks for one-off behavior. Use `MutationCache` callbacks when the app wants a consistent invalidation policy for every mutation.

### Global invalidation after successful mutations

```ts
import { MutationCache, QueryClient } from '@tanstack/react-query'

export const queryClient = new QueryClient({
  mutationCache: new MutationCache({
    onSuccess: (_data, _variables, _context, mutation) => {
      return queryClient.invalidateQueries({
        queryKey: mutation.options.mutationKey,
      })
    },
  }),
})
```

If a mutation has `mutationKey: ['issues']`, this invalidates matching issue queries. If it has no mutation key, this becomes a broad invalidation policy, so only use that deliberately.

### Use meta for explicit invalidation tags

```ts
import { matchQuery, MutationCache, QueryClient } from '@tanstack/react-query'

const queryClient = new QueryClient({
  mutationCache: new MutationCache({
    onSuccess: (_data, _variables, _context, mutation) => {
      return queryClient.invalidateQueries({
        predicate: (query) =>
          mutation.meta?.invalidates?.some((queryKey) =>
            matchQuery({ queryKey }, query),
          ) ?? true,
      })
    },
  }),
})
```

## Common Mistakes

### HIGH Invalidating the whole app for every mutation

Wrong:

```ts
new MutationCache({
  onSuccess: () => queryClient.invalidateQueries(),
})
```

Correct:

```ts
new MutationCache({
  onSuccess: (_data, _variables, _context, mutation) =>
    queryClient.invalidateQueries({ queryKey: mutation.options.mutationKey }),
})
```

Global policies need scope. Reach for mutation keys or meta tags before invalidating everything.

Source: https://tkdodo.eu/blog/automatic-query-invalidation-after-mutations

### HIGH Not returning invalidation when pending UI depends on refetch

Wrong:

```ts
onSuccess: () => {
  queryClient.invalidateQueries({ queryKey: ['todos'] })
}
```

Correct:

```ts
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] })
```

Returning the promise keeps the mutation pending until the invalidation refetch completes.

Source: TanStack/query:docs/framework/react/guides/invalidations-from-mutations.md

### MEDIUM Refetching data that should be static

Wrong:

```ts
useQuery({
  queryKey: ['build-info'],
  queryFn: fetchBuildInfo,
  staleTime: Infinity,
})
```

Correct:

```ts
useQuery({
  queryKey: ['build-info'],
  queryFn: fetchBuildInfo,
  staleTime: 'static',
})
```

If a query must not refetch even after broad manual invalidation, mark it with `staleTime: 'static'`.

Source: https://tkdodo.eu/blog/automatic-query-invalidation-after-mutations

