> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/TanStack/query/llms.txt
> Use this file to discover all available pages before exploring further.

# MutationObserver

> Core class for observing and executing mutations

# MutationObserver

The `MutationObserver` class is used to observe mutations and subscribe to changes in mutation state. This is the core class that powers `useMutation` in framework integrations.

## Import

```tsx theme={null}
import { MutationObserver } from '@tanstack/query-core'
```

## Constructor

```tsx theme={null}
class MutationObserver<
  TData = unknown,
  TError = DefaultError,
  TVariables = void,
  TContext = unknown,
> {
  constructor(
    client: QueryClient,
    options: MutationObserverOptions<TData, TError, TVariables, TContext>
  )
}
```

## Type Parameters

<ParamField path="TData" type="type" default="unknown">
  The type of data returned by the mutation function
</ParamField>

<ParamField path="TError" type="type" default="DefaultError">
  The type of error that can be thrown
</ParamField>

<ParamField path="TVariables" type="type" default="void">
  The type of variables passed to the mutation function
</ParamField>

<ParamField path="TContext" type="type" default="unknown">
  The type of context returned by onMutate
</ParamField>

## Parameters

<ParamField path="client" type="QueryClient" required>
  The QueryClient instance to use
</ParamField>

<ParamField path="options" type="MutationObserverOptions" required>
  Configuration options for the mutation observer

  <ParamField path="mutationFn" type="(variables: TVariables) => Promise<TData>" required>
    The function that performs the mutation
  </ParamField>

  <ParamField path="mutationKey" type="MutationKey">
    Optional unique key for the mutation
  </ParamField>

  <ParamField path="onMutate" type="(variables: TVariables) => Promise<TContext> | TContext">
    Callback fired before mutation function is executed
  </ParamField>

  <ParamField path="onSuccess" type="(data: TData, variables: TVariables, context: TContext) => Promise<unknown> | unknown">
    Callback fired when mutation succeeds
  </ParamField>

  <ParamField path="onError" type="(error: TError, variables: TVariables, context: TContext | undefined) => Promise<unknown> | unknown">
    Callback fired when mutation errors
  </ParamField>

  <ParamField path="onSettled" type="(data: TData | undefined, error: TError | null, variables: TVariables, context: TContext | undefined) => Promise<unknown> | unknown">
    Callback fired when mutation completes (success or error)
  </ParamField>

  <ParamField path="retry" type="boolean | number | (failureCount: number, error: TError) => boolean" default="0">
    Number of retry attempts or function to determine retries
  </ParamField>

  <ParamField path="retryDelay" type="number | (failureCount: number, error: TError) => number">
    Delay between retry attempts
  </ParamField>
</ParamField>

## Methods

### mutate

```tsx theme={null}
mutate(
  variables: TVariables,
  options?: MutateOptions<TData, TError, TVariables, TContext>
): Promise<TData>
```

Execute the mutation with the given variables.

### reset

```tsx theme={null}
reset(): void
```

Reset the mutation observer to its initial state.

### setOptions

```tsx theme={null}
setOptions(
  options: MutationObserverOptions<TData, TError, TVariables, TContext>
): void
```

Update the mutation observer options.

### subscribe

```tsx theme={null}
subscribe(
  listener: (result: MutationObserverResult<TData, TError, TVariables, TContext>) => void
): () => void
```

Subscribe to mutation state changes. Returns an unsubscribe function.

### getCurrentResult

```tsx theme={null}
getCurrentResult(): MutationObserverResult<TData, TError, TVariables, TContext>
```

Get the current mutation result.

## Result Type

```tsx theme={null}
interface MutationObserverResult<TData, TError, TVariables, TContext> {
  context: TContext | undefined
  data: TData | undefined
  error: TError | null
  failureCount: number
  failureReason: TError | null
  isError: boolean
  isIdle: boolean
  isPending: boolean
  isPaused: boolean
  isSuccess: boolean
  mutate: (variables: TVariables, options?: MutateOptions) => void
  mutateAsync: (variables: TVariables, options?: MutateOptions) => Promise<TData>
  reset: () => void
  status: 'idle' | 'pending' | 'error' | 'success'
  submittedAt: number
  variables: TVariables | undefined
}
```

## Examples

### Basic Usage

```tsx theme={null}
import { MutationObserver, QueryClient } from '@tanstack/query-core'

const queryClient = new QueryClient()

const observer = new MutationObserver(queryClient, {
  mutationFn: async (newPost) => {
    const response = await fetch('/api/posts', {
      method: 'POST',
      body: JSON.stringify(newPost),
    })
    return response.json()
  },
})

// Subscribe to changes
const unsubscribe = observer.subscribe((result) => {
  console.log('Mutation state:', result)
})

// Execute mutation
observer.mutate({ title: 'Hello', body: 'World' })

// Clean up
unsubscribe()
```

### With Callbacks

```tsx theme={null}
import { MutationObserver, QueryClient } from '@tanstack/query-core'

const queryClient = new QueryClient()

const observer = new MutationObserver(queryClient, {
  mutationFn: updatePost,
  onMutate: async (variables) => {
    // Cancel outgoing refetches
    await queryClient.cancelQueries({ queryKey: ['posts'] })
    
    // Snapshot previous value
    const previous = queryClient.getQueryData(['posts'])
    
    // Optimistically update
    queryClient.setQueryData(['posts'], (old) => {
      return old.map((post) =>
        post.id === variables.id ? { ...post, ...variables } : post
      )
    })
    
    return { previous }
  },
  onError: (err, variables, context) => {
    // Rollback on error
    queryClient.setQueryData(['posts'], context.previous)
  },
  onSettled: () => {
    // Refetch after mutation
    queryClient.invalidateQueries({ queryKey: ['posts'] })
  },
})
```

### Multiple Subscribers

```tsx theme={null}
import { MutationObserver } from '@tanstack/query-core'

const observer = new MutationObserver(queryClient, {
  mutationFn: createPost,
})

// Multiple components can subscribe
const unsubscribe1 = observer.subscribe((result) => {
  console.log('Subscriber 1:', result.status)
})

const unsubscribe2 = observer.subscribe((result) => {
  console.log('Subscriber 2:', result.status)
})

// Both subscribers will be notified
observer.mutate(newPost)

// Clean up
unsubscribe1()
unsubscribe2()
```

### Updating Options

```tsx theme={null}
import { MutationObserver } from '@tanstack/query-core'

const observer = new MutationObserver(queryClient, {
  mutationFn: createPost,
})

// Update options later
observer.setOptions({
  mutationFn: createPost,
  onSuccess: (data) => {
    console.log('Post created:', data)
  },
})
```

### Manual State Management

```tsx theme={null}
import { MutationObserver } from '@tanstack/query-core'

const observer = new MutationObserver(queryClient, {
  mutationFn: updateUser,
})

// Get current state
const result = observer.getCurrentResult()
console.log('Status:', result.status)
console.log('Data:', result.data)
console.log('Error:', result.error)

// Reset to initial state
observer.reset()
```

### With Retry Logic

```tsx theme={null}
import { MutationObserver } from '@tanstack/query-core'

const observer = new MutationObserver(queryClient, {
  mutationFn: createPost,
  retry: 3,
  retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000),
})
```

## Notes

* `MutationObserver` is the low-level class that framework integrations build upon
* In React, `useMutation` creates and manages a `MutationObserver` instance
* Observers can have multiple subscribers
* The observer manages a single mutation instance at a time
* Calling `mutate()` multiple times creates new mutation instances
* Each mutation instance has its own state and lifecycle
* The observer automatically handles retry logic based on configuration
* Subscribers are notified synchronously when state changes
