Fetch and cache data with the createQuery function. It returns a reactive query result that automatically updates when dependencies change in Svelte 5’s runes mode.
Signature
function createQuery < TQueryFnData , TError , TData , TQueryKey >(
options : Accessor < CreateQueryOptions < TQueryFnData , TError , TData , TQueryKey >>,
queryClient ?: Accessor < QueryClient >,
) : CreateQueryResult < TData , TError >
Parameters
options
Accessor<CreateQueryOptions<TQueryFnData, TError, TData, TQueryKey>>
required
A function (accessor) returning query configuration options. Unique identifier for the query. Changes trigger automatic refetch.
queryFn
QueryFunction<TQueryFnData, TQueryKey>
required
Function that fetches the data.
Set to false to disable automatic query execution.
Time in milliseconds until cached data is considered stale.
Time in milliseconds before unused data is garbage collected.
Interval in milliseconds for automatic refetching.
Refetch when window regains focus.
Refetch when network reconnects.
Number of retry attempts or boolean to enable/disable retries.
select
(data: TQueryData) => TData
Transform or select a part of the data.
Initial data to use before the query executes.
Placeholder data while the query is loading.
Accessor returning a custom QueryClient instance. If not provided, uses the client from context.
Returns
CreateQueryResult<TData, TError>
Reactive query state accessible via Svelte runes. The query result data. Returns undefined if not yet loaded.
The error object if the query failed.
true when fetching for the first time (no cached data).
true whenever the query is fetching (including background refetches).
true when the query has successfully fetched data.
true when the query encountered an error.
true when the query is pending (no data and no error yet).
status
'pending' | 'error' | 'success'
The current status of the query.
fetchStatus
'fetching' | 'paused' | 'idle'
The fetch status of the query.
refetch
() => Promise<QueryObserverResult>
Manually trigger a refetch of the query.
Type Parameters
TQueryFnData - Type returned by the query function
TError - Type of error (defaults to DefaultError)
TData - Type of data returned (defaults to TQueryFnData)
TQueryKey - Type of the query key (defaults to QueryKey)
Examples
Basic Usage (Svelte 5 Runes)
< script lang = "ts" >
import { createQuery } from '@tanstack/svelte-query'
const query = createQuery (() => ({
queryKey: [ 'todos' ],
queryFn : async () => {
const res = await fetch ( '/api/todos' )
return res . json ()
},
}))
</ script >
{# if query . isLoading }
< div > Loading... </ div >
{: else if query . error }
< div > Error: { query . error . message } </ div >
{: else if query . data }
< ul >
{# each query . data as todo }
< li > { todo . title } </ li >
{/ each }
</ ul >
{/ if }
Reactive Query Keys
< script lang = "ts" >
import { createQuery } from '@tanstack/svelte-query'
let todoId = $ state ( 1 )
// Query automatically refetches when todoId changes
const query = createQuery (() => ({
queryKey: [ 'todo' , todoId ],
queryFn : async () => {
const res = await fetch ( `/api/todos/ ${ todoId } ` )
return res . json ()
},
}))
function nextTodo () {
todoId ++
}
</ script >
< button onclick = { nextTodo } > Next Todo </ button >
{# if query . data }
< h2 > { query . data . title } </ h2 >
{/ if }
With TypeScript
< script lang = "ts" >
import { createQuery } from '@tanstack/svelte-query'
interface Todo {
id : number
title : string
completed : boolean
}
const query = createQuery (() => ({
queryKey: [ 'todos' ],
queryFn : async () : Promise < Todo []> => {
const res = await fetch ( '/api/todos' )
return res . json ()
},
}))
// query.data is typed as Todo[] | undefined
</ script >
Conditional Fetching
< script lang = "ts" >
import { createQuery } from '@tanstack/svelte-query'
let userId = $ state < number | null >( null )
const query = createQuery (() => ({
queryKey: [ 'user' , userId ],
queryFn : () => fetchUser ( userId ! ),
enabled: userId !== null , // Only fetch when userId is set
}))
</ script >
With Select
< script lang = "ts" >
import { createQuery } from '@tanstack/svelte-query'
const query = createQuery (() => ({
queryKey: [ 'todos' ],
queryFn: fetchTodos ,
select : ( todos ) => todos . filter ( todo => ! todo . completed ),
}))
// query.data only contains incomplete todos
</ script >
Dependent Queries
< script lang = "ts" >
import { createQuery } from '@tanstack/svelte-query'
// First query
const userQuery = createQuery (() => ({
queryKey: [ 'user' ],
queryFn: fetchUser ,
}))
// Second query depends on first
const projectsQuery = createQuery (() => ({
queryKey: [ 'projects' , userQuery . data ?. id ],
queryFn : () => fetchProjects ( userQuery . data ! . id ),
enabled: !! userQuery . data ?. id ,
}))
</ script >
Initial Data
< script lang = "ts" >
import { createQuery } from '@tanstack/svelte-query'
interface Props {
todoId : number
initialTodo ?: Todo
}
let { todoId , initialTodo } : Props = $ props ()
const query = createQuery (() => ({
queryKey: [ 'todo' , todoId ],
queryFn : () => fetchTodo ( todoId ),
initialData: initialTodo ,
}))
</ script >
Polling/Refetch Interval
< script lang = "ts" >
import { createQuery } from '@tanstack/svelte-query'
const query = createQuery (() => ({
queryKey: [ 'realtime-data' ],
queryFn: fetchRealtimeData ,
refetchInterval: 5000 , // Refetch every 5 seconds
}))
</ script >
Manual Refetch
< script lang = "ts" >
import { createQuery } from '@tanstack/svelte-query'
const query = createQuery (() => ({
queryKey: [ 'data' ],
queryFn: fetchData ,
}))
function refresh () {
query . refetch ()
}
</ script >
< button onclick = { refresh } > Refresh Data </ button >
{# if query . data }
< pre > { JSON . stringify ( query . data , null , 2 ) } </ pre >
{/ if }
Error Handling
< script lang = "ts" >
import { createQuery } from '@tanstack/svelte-query'
const query = createQuery (() => ({
queryKey: [ 'data' ],
queryFn: fetchData ,
retry: 3 ,
retryDelay : ( attemptIndex ) => Math . min ( 1000 * 2 ** attemptIndex , 30000 ),
}))
</ script >
{# if query . isError }
< div >
< p > Error: { query . error ?. message } </ p >
< button onclick = { () => query . refetch () } > Try Again </ button >
</ div >
{: else }
<!-- Success content -->
{/ if }
Multiple Reactive Dependencies
< script lang = "ts" >
import { createQuery } from '@tanstack/svelte-query'
let filter = $ state ( 'all' )
let page = $ state ( 1 )
// Query refetches when either filter or page changes
const query = createQuery (() => ({
queryKey: [ 'todos' , filter , page ],
queryFn : async () => {
const res = await fetch ( `/api/todos?filter= ${ filter } &page= ${ page } ` )
return res . json ()
},
}))
</ script >
< select bind : value = { filter } >
< option value = "all" > All </ option >
< option value = "active" > Active </ option >
< option value = "completed" > Completed </ option >
</ select >
< button onclick = { () => page -- } disabled = { page === 1 } > Previous </ button >
< button onclick = { () => page ++ } > Next </ button >
With Loading States
< script lang = "ts" >
import { createQuery } from '@tanstack/svelte-query'
const query = createQuery (() => ({
queryKey: [ 'todos' ],
queryFn: fetchTodos ,
}))
</ script >
{# if query . isLoading }
< div class = "spinner" > Loading... </ div >
{: else if query . isError }
< div class = "error" >
< h3 > Error occurred </ h3 >
< p > { query . error . message } </ p >
</ div >
{: else if query . isSuccess }
< div class = "success" >
<!-- Render data -->
</ div >
{/ if }
Notes
Svelte Query uses Svelte 5’s runes mode. The options parameter must be an accessor (function) to track reactive dependencies.
Access query state properties directly (e.g., query.data, query.isLoading) without needing to use $state or stores.
Make sure to use Svelte 5 with runes mode enabled. Svelte Query v5+ requires Svelte 5.