Skip to main content
Fetch and cache data with the createQuery primitive. It returns a reactive query result that automatically updates when dependencies change in SolidJS.

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 Solid accessor (function) returning query configuration options.
queryClient
Accessor<QueryClient>
Accessor returning a custom QueryClient instance. If not provided, uses the client from context.

Returns

CreateQueryResult<TData, TError>
object
Reactive query state that updates automatically.

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

import { createQuery } from '@tanstack/solid-query'
import { For, Show } from 'solid-js'

function TodoList() {
  const query = createQuery(() => ({
    queryKey: ['todos'],
    queryFn: async () => {
      const res = await fetch('/api/todos')
      return res.json()
    },
  }))

  return (
    <div>
      <Show when={query.isLoading}>
        <div>Loading...</div>
      </Show>
      
      <Show when={query.error}>
        <div>Error: {query.error.message}</div>
      </Show>
      
      <Show when={query.data}>
        <ul>
          <For each={query.data}>
            {(todo) => <li>{todo.title}</li>}
          </For>
        </ul>
      </Show>
    </div>
  )
}

Reactive Query Keys

import { createSignal } from 'solid-js'
import { createQuery } from '@tanstack/solid-query'

function TodoDetail() {
  const [todoId, setTodoId] = createSignal(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()
    },
  }))

  return (
    <div>
      <button onClick={() => setTodoId(id => id + 1)}>
        Next Todo
      </button>
      <Show when={query.data}>
        <h2>{query.data.title}</h2>
      </Show>
    </div>
  )
}

With TypeScript

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

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

function TodoList() {
  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

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

Conditional Fetching

import { createSignal } from 'solid-js'
import { createQuery } from '@tanstack/solid-query'

function UserProfile() {
  const [userId, setUserId] = createSignal<number | null>(null)

  const query = createQuery(() => ({
    queryKey: ['user', userId()],
    queryFn: () => fetchUser(userId()!),
    enabled: userId() !== null, // Only fetch when userId is set
  }))

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

With Select

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

function IncompleteTodos() {
  const query = createQuery(() => ({
    queryKey: ['todos'],
    queryFn: fetchTodos,
    select: (todos) => todos.filter(todo => !todo.completed),
  }))

  // query.data only contains incomplete todos

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

Dependent Queries

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

function UserProjects() {
  // 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,
  }))

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

Initial Data

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

function TodoDetail(props: { todoId: number; initialTodo?: Todo }) {
  const query = createQuery(() => ({
    queryKey: ['todo', props.todoId],
    queryFn: () => fetchTodo(props.todoId),
    initialData: props.initialTodo,
  }))

  // query.data starts with initialTodo if provided

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

Polling/Refetch Interval

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

function RealtimeData() {
  const query = createQuery(() => ({
    queryKey: ['realtime-data'],
    queryFn: fetchRealtimeData,
    refetchInterval: 5000, // Refetch every 5 seconds
  }))

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

Manual Refetch

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

function ManualRefetch() {
  const query = createQuery(() => ({
    queryKey: ['data'],
    queryFn: fetchData,
  }))

  return (
    <div>
      <button onClick={() => query.refetch()}>
        Refresh Data
      </button>
      <Show when={query.data}>
        <pre>{JSON.stringify(query.data, null, 2)}</pre>
      </Show>
    </div>
  )
}

Error Handling

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

function ErrorHandling() {
  const query = createQuery(() => ({
    queryKey: ['data'],
    queryFn: fetchData,
    retry: 3,
    retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000),
  }))

  return (
    <Show 
      when={!query.isError}
      fallback={
        <div>
          <p>Error: {query.error?.message}</p>
          <button onClick={() => query.refetch()}>Try Again</button>
        </div>
      }
    >
      {/* Success content */}
    </Show>
  )
}

Notes

The options parameter must be an accessor (function). This allows SolidJS to track dependencies and automatically refetch when reactive values change.
Use createMemo if you need to derive query options from multiple signals:
const queryOptions = createMemo(() => ({
  queryKey: ['data', filter(), page()],
  queryFn: () => fetchData(filter(), page()),
}))

const query = createQuery(queryOptions)

Build docs developers (and LLMs) love