Form submission
Submitting a form that creates or updates server data.
TanStack · Hook
useMutation configures and runs server-side writes such as creating, updating, or deleting data. It returns mutation state and commands for triggering, awaiting, or resetting the operation.
useMutation creates a mutation controller for server-side writes and other effects. Configure its mutation function and lifecycle callbacks, then call mutate with one variables value; the returned result exposes status, data, errors, reset, and promise-based mutateAsync behavior.
function useMutation<TData, TError, TVariables, TOnMutateResult>(options: UseMutationOptions<TData, TError, TVariables, TOnMutateResult>, queryClient?: QueryClient): UseMutationResult<TData, TError, TVariables, TOnMutateResult>;| Name | Type | Description |
|---|---|---|
options | UseMutationOptions<TData, TError, TVariables, TOnMutateResult> | The mutation configuration, including the mutation function and lifecycle options. |
queryClient | QueryClient | Optional custom client; otherwise the client from the nearest context is used. |
UseMutationResult<TData, TError, TVariables, TOnMutateResult>
import { useMutation, useQueryClient } from '@tanstack/react-query'
async function addTodo(title: string) {
const response = await fetch('/api/todos', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ title }),
})
if (!response.ok) throw new Error('Request failed')
return response.json() as Promise<{ id: string; title: string }>
}
export function AddTodo() {
const queryClient = useQueryClient()
const mutation = useMutation({
mutationFn: addTodo,
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
})
return <button onClick={() => mutation.mutate('Learn TanStack Query')}>
{mutation.isPending ? 'Adding…' : 'Add todo'}
</button>
}Defines a server-side create operation, starts it with mutate, and invalidates the todos query after success.
Submitting a form that creates or updates server data.
Updating cached queries after a successful write.
Showing immediate UI changes while a write is in flight and rolling them back if it fails.
useMutation is intended for create, update, delete, and other server side-effects rather than fetching query data. Its options define the mutation function and lifecycle behavior, while the returned object exposes controls and state.
Follow-up: How should a successful write update displayed query data? Invalidate or refetch the affected queries from a lifecycle callback such as onSuccess.
mutate starts the mutation and accepts one variables argument plus optional per-call callbacks. mutateAsync provides a promise that resolves on success and throws when the mutation fails.
Follow-up: When is mutate preferable? Use it for event-driven actions where the component can react through mutation state or callbacks without awaiting a promise.
onMutate runs before the mutation and can return a value passed to later callbacks. That value can carry information needed to undo an optimistic update when onError runs.
Follow-up: What should an optimistic-update implementation do after failure? Restore the previous cached value using the onMutate result, then reconcile or invalidate the relevant query.
UseMutationOptionsUseMutationResultQueryClientmutatemutateAsyncMutationCacheuseQueryClient