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 function. It provides methods to trigger mutations and tracks their state reactively in Svelte 5.

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 function (accessor) 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 (Svelte 5 Runes)

<script lang="ts">
import { createMutation, useQueryClient } from '@tanstack/svelte-query'

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'] })
  },
}))

function handleCreate() {
  mutation.mutate({ title: 'New Todo', completed: false })
}
</script>

<button onclick={handleCreate} disabled={mutation.isPending}>
  {mutation.isPending ? 'Adding...' : 'Add Todo'}
</button>

{#if mutation.isError}
  <div>Error: {mutation.error?.message}</div>
{/if}

With TypeScript

<script lang="ts">
import { createMutation } from '@tanstack/svelte-query'

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

interface CreateTodoVariables {
  title: string
  completed: boolean
}

const mutation = createMutation(() => ({
  mutationFn: async (variables: CreateTodoVariables): Promise<Todo> => {
    const res = await fetch('/api/todos', {
      method: 'POST',
      body: JSON.stringify(variables),
    })
    return res.json()
  },
}))

function handleCreate() {
  // Type-safe mutation call
  mutation.mutate({ title: 'Learn Svelte Query', completed: false })
}
</script>

Optimistic Updates

<script lang="ts">
import { createMutation, useQueryClient } from '@tanstack/svelte-query'

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'] })
  },
}))
</script>

Using mutateAsync

<script lang="ts">
import { createMutation } from '@tanstack/svelte-query'

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

async function handleSubmit() {
  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)
  }
}
</script>

<button onclick={handleSubmit}>Submit</button>

Per-Mutation Callbacks

<script lang="ts">
import { createMutation } from '@tanstack/svelte-query'

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

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

Reset Mutation State

<script lang="ts">
import { createMutation } from '@tanstack/svelte-query'

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

function handleCreate() {
  mutation.reset() // Reset previous state
  mutation.mutate({ title: 'New Todo' })
}
</script>

<button onclick={handleCreate}>Create</button>

{#if mutation.isSuccess}
  <div>Successfully created!</div>
{/if}

Multiple Mutations

<script lang="ts">
import { createMutation, useQueryClient } from '@tanstack/svelte-query'

const queryClient = useQueryClient()

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

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

<button 
  onclick={() => createMutation.mutate({ title: 'New' })}
  disabled={createMutation.isPending}
>
  Create
</button>

<button 
  onclick={() => deleteMutation.mutate(1)}
  disabled={deleteMutation.isPending}
>
  Delete
</button>

Error Handling with Retry

<script lang="ts">
import { createMutation } from '@tanstack/svelte-query'

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

Reactive Mutation Options

<script lang="ts">
import { createMutation } from '@tanstack/svelte-query'

let shouldRetry = $state(true)

const mutation = createMutation(() => ({
  mutationFn: createTodo,
  retry: shouldRetry ? 3 : 0,
}))
</script>

<label>
  <input type="checkbox" bind:checked={shouldRetry} />
  Enable retry
</label>

Form Handling

<script lang="ts">
import { createMutation } from '@tanstack/svelte-query'

let title = $state('')

const mutation = createMutation(() => ({
  mutationFn: createTodo,
  onSuccess: () => {
    title = '' // Clear form on success
  },
}))

function handleSubmit(e: Event) {
  e.preventDefault()
  mutation.mutate({ title, completed: false })
}
</script>

<form onsubmit={handleSubmit}>
  <input 
    type="text" 
    bind:value={title} 
    placeholder="Todo title"
    disabled={mutation.isPending}
  />
  <button type="submit" disabled={mutation.isPending}>
    {mutation.isPending ? 'Adding...' : 'Add Todo'}
  </button>
</form>

{#if mutation.isError}
  <p class="error">{mutation.error?.message}</p>
{/if}

{#if mutation.isSuccess}
  <p class="success">Todo added successfully!</p>
{/if}

Loading States

<script lang="ts">
import { createMutation } from '@tanstack/svelte-query'

const mutation = createMutation(() => ({
  mutationFn: createTodo,
}))
</script>

<button onclick={() => mutation.mutate({ title: 'New' })}>
  Create Todo
</button>

{#if mutation.isPending}
  <div>Creating...</div>
{:else if mutation.isError}
  <div>Error: {mutation.error?.message}</div>
{:else if mutation.isSuccess}
  <div>Todo created successfully!</div>
{/if}

Notes

Svelte Query uses Svelte 5’s runes mode. The options parameter must be an accessor (function).
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