# Mutations and Invalidation

> Write through a mutation, invalidate the queries it affects, and let dependents refetch.

Source: [https://askrjs.com/docs/data/mutations-and-invalidation](https://askrjs.com/docs/data/mutations-and-invalidation)

Status: stable. Packages: @askrjs/askr/data.

**Published packages are authoritative.** Examples may lag behind a published contract. When guidance differs, verify the exports and TypeScript declarations in your installed package, then file an issue.

## Example

Describe the write, the cache prefixes it affects, and whether successful writes invalidate those prefixes.

```tsx
import { createMutation } from '@askrjs/askr/data';

const renameProject = createMutation<
  { id: string; name: string },
  Project
>({
  action: ({ id, name }, { signal }) => api.projects.rename(id, name, { signal }),
  affects: ({ id }) => ['project:' + id, 'projects'],
  afterSuccess: 'invalidate',
});

async function rename(id: string, name: string) {
  return renameProject.execute({ id, name });
}
```

## Create a mutation

createMutation(options) takes an action(input, { signal }) function that performs the write and returns the result. What comes back is a Mutation&lt;TInput, TResult&gt; with execute(input), abort(), and reset() methods, plus status fields you read directly rather than through a callback.

## Write lifecycle

A mutation's status is always one of 'idle', 'pending', 'success', or 'error', and the pending/error/result fields line up with whichever status you're in — result is only populated once status is 'success', error only once it's 'error'. Calling reset() puts it back to idle, and abort() cancels an in-flight execute() via the signal passed into the action function.

## Targeted invalidation

The affects(input, result) option on MutationOptions maps a completed write to the list of query key prefixes it should invalidate — but only when the mutation's afterSuccess option is 'invalidate' (the setting that opts into automatic invalidation at all); with a different afterSuccess setting, affects() is never called and nothing gets invalidated on your behalf. For writes that happen outside a mutation entirely, invalidate(prefix, options) and queryScope().invalidate() are available directly, and invalidateOnInterval() covers periodic invalidation gated by options like visibleOnly or focusedOnly.

## Optimistic UI

There's no dedicated optimistic-value API on MutationOptions — no optimisticData field to set. Optimistic UI is built by hand: keep local state for the value you're predicting, render it while mutation.status is 'pending', and reconcile or roll it back once status settles to 'success' or 'error'. The afterSuccess: 'invalidate' option can be paired with this to refetch the real data as soon as the write completes, replacing your optimistic guess with the server's actual response.

## Documentation navigation

[Previous](https://askrjs.com/docs/data/queries-and-consistency/index.md) | [Next](https://askrjs.com/docs/data/server-queries/index.md)
