Skip to main content

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 createMutation primitive. It provides methods to trigger mutations and tracks their state reactively in SolidJS.

Signature

function createMutation<TData, TError, TVariables, TContext>(
  options: Accessor<CreateMutationOptions<TData, TError, TVariables, TContext>>,
  queryClient?: Accessor<QueryClient>,
): CreateMutationResult<TData, TError, TVariables, TContext>

Parameters

options
Accessor<CreateMutationOptions<TData, TError, TVariables, TContext>>
required
A Solid accessor (function) returning mutation configuration options.
queryClient
Accessor<QueryClient>
Accessor returning a custom QueryClient instance. If not provided, uses the client from context.

Returns

CreateMutationResult<TData, TError, TVariables, TContext>
object
Reactive mutation state and methods.

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

import { createMutation, useQueryClient } from '@tanstack/solid-query'
import { Show } from 'solid-js'

function CreateTodo() {
  const queryClient = useQueryClient()

  const mutation = createMutation(() => ({
    mutationFn: async (newTodo) => {
      const res = await fetch('/api/todos', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(newTodo),
      })
      return res.json()
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['todos'] })
    },
  }))

  const handleCreate = () => {
    mutation.mutate({ title: 'New Todo', completed: false })
  }

  return (
    <div>
      <button onClick={handleCreate} disabled={mutation.isPending}>
        {mutation.isPending ? 'Adding...' : 'Add Todo'}
      </button>
      <Show when={mutation.isError}>
        <div>Error: {mutation.error?.message}</div>
      </Show>
    </div>
  )
}

With TypeScript

import { createMutation } from '@tanstack/solid-query'

interface Todo {
  id: number
  title: string
  completed: boolean
}

interface CreateTodoVariables {
  title: string
  completed: boolean
}

function CreateTodo() {
  const mutation = createMutation(() => ({
    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
  const handleCreate = () => {
    mutation.mutate({ title: 'Learn Solid Query', completed: false })
  }

  return <button onClick={handleCreate}>Create</button>
}

Optimistic Updates

import { createMutation, useQueryClient } from '@tanstack/solid-query'

function UpdateTodo() {
  const queryClient = useQueryClient()

  const mutation = createMutation(() => ({
    mutationFn: updateTodo,
    onMutate: async (updatedTodo) => {
      // 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 === updatedTodo.id ? updatedTodo : todo
        )
      })
      
      // Return context with snapshot
      return { previousTodos }
    },
    onError: (err, updatedTodo, context) => {
      // Rollback on error
      if (context?.previousTodos) {
        queryClient.setQueryData(['todos'], context.previousTodos)
      }
    },
    onSettled: () => {
      // Always refetch after error or success
      queryClient.invalidateQueries({ queryKey: ['todos'] })
    },
  }))

  return <div>{/* ... */}</div>
}

Using mutateAsync

import { createMutation } from '@tanstack/solid-query'

function CreateTodo() {
  const mutation = createMutation(() => ({
    mutationFn: createTodo,
  }))

  const handleSubmit = async () => {
    try {
      const newTodo = await mutation.mutateAsync({ title: 'New Todo' })
      console.log('Created todo:', newTodo)
      // Navigate or show success message
    } catch (error) {
      console.error('Failed to create todo:', error)
    }
  }

  return <button onClick={handleSubmit}>Submit</button>
}

Per-Mutation Callbacks

import { createMutation } from '@tanstack/solid-query'

function CreateTodo() {
  const mutation = createMutation(() => ({
    mutationFn: createTodo,
  }))

  const handleCreate = () => {
    mutation.mutate(
      { title: 'New Todo' },
      {
        onSuccess: (data) => {
          console.log('Created:', data)
        },
        onError: (error) => {
          console.error('Failed:', error)
        },
      }
    )
  }

  return <button onClick={handleCreate}>Create</button>
}

Reset Mutation State

import { createMutation } from '@tanstack/solid-query'
import { Show } from 'solid-js'

function CreateTodo() {
  const mutation = createMutation(() => ({
    mutationFn: createTodo,
  }))

  const handleCreate = () => {
    mutation.reset() // Reset previous state
    mutation.mutate({ title: 'New Todo' })
  }

  return (
    <div>
      <button onClick={handleCreate}>Create</button>
      <Show when={mutation.isSuccess}>
        <div>Successfully created!</div>
      </Show>
    </div>
  )
}

Multiple Mutations

import { createMutation, useQueryClient } from '@tanstack/solid-query'

function TodoActions() {
  const queryClient = useQueryClient()

  const createMutation = createMutation(() => ({
    mutationFn: createTodo,
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['todos'] })
    },
  }))

  const deleteMutation = createMutation(() => ({
    mutationFn: deleteTodo,
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['todos'] })
    },
  }))

  return (
    <div>
      <button 
        onClick={() => createMutation.mutate({ title: 'New' })}
        disabled={createMutation.isPending}
      >
        Create
      </button>
      <button 
        onClick={() => deleteMutation.mutate(1)}
        disabled={deleteMutation.isPending}
      >
        Delete
      </button>
    </div>
  )
}

Error Handling with Retry

import { createMutation } from '@tanstack/solid-query'

function CreateTodo() {
  const mutation = createMutation(() => ({
    mutationFn: createTodo,
    retry: 3,
    retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000),
    onError: (error) => {
      console.error('Mutation failed after retries:', error)
    },
  }))

  return <div>{/* ... */}</div>
}

Reactive Mutation Options

import { createSignal, createMemo } from 'solid-js'
import { createMutation } from '@tanstack/solid-query'

function CreateTodo() {
  const [shouldRetry, setShouldRetry] = createSignal(true)

  const mutationOptions = createMemo(() => ({
    mutationFn: createTodo,
    retry: shouldRetry() ? 3 : 0,
  }))

  const mutation = createMutation(mutationOptions)

  return <div>{/* ... */}</div>
}

Mutation with Loading State

import { createMutation } from '@tanstack/solid-query'
import { Show, Switch, Match } from 'solid-js'

function CreateTodo() {
  const mutation = createMutation(() => ({
    mutationFn: createTodo,
  }))

  return (
    <div>
      <button onClick={() => mutation.mutate({ title: 'New' })}>
        Create Todo
      </button>
      
      <Switch>
        <Match when={mutation.isPending}>
          <div>Creating...</div>
        </Match>
        <Match when={mutation.isError}>
          <div>Error: {mutation.error?.message}</div>
        </Match>
        <Match when={mutation.isSuccess}>
          <div>Todo created successfully!</div>
        </Match>
      </Switch>
    </div>
  )
}

Notes

The options parameter must be an accessor (function) to integrate with SolidJS reactivity system.
Use mutate for fire-and-forget operations and mutateAsync when you need to await the result or handle errors with try/catch.
Always invalidate or update relevant queries after a successful mutation to keep your UI in sync with the server state.

Build docs developers (and LLMs) love