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.
Perform mutations and side effects with the useMutation composable. It provides methods to trigger mutations and tracks their state reactively.
Signature
function useMutation<TData, TError, TVariables, TContext>(
options: UseMutationOptions<TData, TError, TVariables, TContext>,
queryClient?: QueryClient,
): UseMutationReturnType<TData, TError, TVariables, TContext>
Parameters
options
UseMutationOptions<TData, TError, TVariables, TContext>
required
Configuration options for the mutation. Can be a reactive ref or getter function.
mutationFn
MaybeRefDeep<(variables: TVariables) => Promise<TData>>
required
The function that performs the mutation. Can be a ref.
onMutate
MaybeRefDeep<(variables: TVariables) => Promise<TContext> | TContext>
Called before mutation executes. Useful for optimistic updates. Can be a ref.
onSuccess
MaybeRefDeep<(data: TData, variables: TVariables, context: TContext) => void>
Called when mutation succeeds. Can be a ref.
onError
MaybeRefDeep<(error: TError, variables: TVariables, context: TContext | undefined) => void>
Called when mutation fails. Can be a ref.
onSettled
MaybeRefDeep<(data: TData | undefined, error: TError | null, variables: TVariables, context: TContext | undefined) => void>
Called when mutation completes (success or error). Can be a ref.
retry
MaybeRefDeep<number | boolean>
Number of retry attempts or boolean to enable/disable retries. Can be a ref.
retryDelay
MaybeRefDeep<number | ((attemptIndex: number) => number)>
Delay between retry attempts. Can be a ref.
Throw errors instead of setting error state. Can be a ref.
Return state in shallow refs (improves performance if state doesn’t need deep reactivity).
Custom QueryClient instance. If not provided, uses the client from context.
Returns
UseMutationReturnType<TData, TError, TVariables, TContext>
Reactive refs containing mutation state and methods.
mutate
(variables: TVariables, options?: MutateOptions) => void
Trigger the mutation. Fire-and-forget style (doesn’t return a promise).
mutateAsync
(variables: TVariables, options?: MutateOptions) => Promise<TData>
Trigger the mutation and return a promise.
The mutation result data.
The error object if the mutation failed.
true when the mutation is currently executing.
true when the mutation has succeeded.
true when the mutation has failed.
true when the mutation is idle (not executing).
status
Ref<'idle' | 'pending' | 'error' | 'success'>
The current status of the mutation.
variables
Ref<TVariables | undefined>
The variables passed to the mutation.
Reset the mutation state to initial values.
Type Parameters
TData - Type of data returned by the mutation
TError - Type of error (defaults to DefaultError)
TVariables - Type of variables passed to the mutation (defaults to void)
TContext - Type of context returned by onMutate (defaults to unknown)
Examples
Basic Usage
<script setup>
import { useMutation, useQueryClient } from '@tanstack/vue-query'
const queryClient = useQueryClient()
const { mutate, isPending, isError, error } = useMutation({
mutationFn: async (newTodo) => {
const res = await fetch('/api/todos', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(newTodo),
})
return res.json()
},
onSuccess: () => {
// Invalidate and refetch
queryClient.invalidateQueries({ queryKey: ['todos'] })
},
})
const addTodo = () => {
mutate({ title: 'New Todo', completed: false })
}
</script>
<template>
<div>
<button @click="addTodo" :disabled="isPending">
{{ isPending ? 'Adding...' : 'Add Todo' }}
</button>
<div v-if="isError">Error: {{ error.message }}</div>
</div>
</template>
With TypeScript
<script setup lang="ts">
import { useMutation } from '@tanstack/vue-query'
interface Todo {
id: number
title: string
completed: boolean
}
interface CreateTodoVariables {
title: string
completed: boolean
}
const { mutate } = useMutation({
mutationFn: async (variables: CreateTodoVariables): Promise<Todo> => {
const res = await fetch('/api/todos', {
method: 'POST',
body: JSON.stringify(variables),
})
return res.json()
},
})
// Type-safe mutation call
mutate({ title: 'Learn Vue Query', completed: false })
</script>
Optimistic Updates
<script setup>
import { useMutation, useQueryClient } from '@tanstack/vue-query'
const queryClient = useQueryClient()
const { mutate } = useMutation({
mutationFn: updateTodo,
onMutate: async (newTodo) => {
// Cancel outgoing refetches
await queryClient.cancelQueries({ queryKey: ['todos'] })
// Snapshot previous value
const previousTodos = queryClient.getQueryData(['todos'])
// Optimistically update cache
queryClient.setQueryData(['todos'], (old) => {
return old.map(todo =>
todo.id === newTodo.id ? newTodo : todo
)
})
// Return context with snapshot
return { previousTodos }
},
onError: (err, newTodo, context) => {
// Rollback on error
queryClient.setQueryData(['todos'], context.previousTodos)
},
onSettled: () => {
// Always refetch after error or success
queryClient.invalidateQueries({ queryKey: ['todos'] })
},
})
</script>
Using mutateAsync
<script setup>
import { useMutation } from '@tanstack/vue-query'
import { ref } from 'vue'
const { mutateAsync, isPending } = useMutation({
mutationFn: createTodo,
})
const handleSubmit = async () => {
try {
const newTodo = await mutateAsync({ title: 'New Todo' })
console.log('Created todo:', newTodo)
// Navigate or show success message
} catch (error) {
console.error('Failed to create todo:', error)
}
}
</script>
Per-Mutation Callbacks
<script setup>
import { useMutation } from '@tanstack/vue-query'
const { mutate } = useMutation({
mutationFn: createTodo,
})
// Pass callbacks per mutation call
const handleCreate = () => {
mutate(
{ title: 'New Todo' },
{
onSuccess: (data) => {
console.log('Created:', data)
},
onError: (error) => {
console.error('Failed:', error)
},
}
)
}
</script>
Reactive Mutation Options
<script setup>
import { ref, computed } from 'vue'
import { useMutation } from '@tanstack/vue-query'
const retryCount = ref(3)
// Options can be reactive
const mutationOptions = computed(() => ({
mutationFn: createTodo,
retry: retryCount.value,
}))
const { mutate } = useMutation(mutationOptions)
</script>
Reset Mutation State
<script setup>
import { useMutation } from '@tanstack/vue-query'
const { mutate, reset, isSuccess, error } = useMutation({
mutationFn: createTodo,
})
const handleCreate = () => {
// Reset previous state before new mutation
reset()
mutate({ title: 'New Todo' })
}
</script>