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
A function (accessor) returning mutation configuration options.
Show properties
Show properties
The function that performs the mutation.
Called before mutation executes. Useful for optimistic updates. Return context value.
Called when mutation succeeds.
Called when mutation fails.
onSettled
(data: TData | undefined, error: TError | null, variables: TVariables, context: TContext | undefined) => void
Called when mutation completes (success or error).
Number of retry attempts or boolean to enable/disable retries.
Delay between retry attempts.
Throw errors instead of setting error state.
Accessor returning a custom QueryClient instance. If not provided, uses the client from context.
Returns
Reactive mutation state and methods.
Show properties
Show properties
Trigger the mutation. Fire-and-forget style (doesn’t return a promise).
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).The current status of the mutation.
The variables passed to the mutation.
Reset the mutation state to initial values.
Type Parameters
TData- Type of data returned by the mutationTError- Type of error (defaults toDefaultError)TVariables- Type of variables passed to the mutation (defaults tovoid)TContext- Type of context returned byonMutate(defaults tounknown)
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.
Related
- createQuery - For fetching data
- Mutations Guide - Detailed guide on mutations