Skip to main content
The useQuery hook is the primary way to fetch data in TanStack Query. It manages the lifecycle of a query, including caching, background updates, and stale data management.

Import

import { useQuery } from '@tanstack/react-query'

Signature

function useQuery<
  TQueryFnData = unknown,
  TError = DefaultError,
  TData = TQueryFnData,
  TQueryKey extends QueryKey = QueryKey,
>(
  options: UseQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
  queryClient?: QueryClient,
): UseQueryResult<TData, TError>

Parameters

options
object
required
The query options object.
queryClient
QueryClient
Use this to override the default QueryClient.

Returns

UseQueryResult<TData, TError>
object
The query result object.

Examples

Basic Usage

import { useQuery } from '@tanstack/react-query'

function Todos() {
  const { data, isLoading, error } = useQuery({
    queryKey: ['todos'],
    queryFn: async () => {
      const response = await fetch('/api/todos')
      if (!response.ok) throw new Error('Network response was not ok')
      return response.json()
    },
  })

  if (isLoading) return <div>Loading...</div>
  if (error) return <div>Error: {error.message}</div>

  return (
    <ul>
      {data.map(todo => (
        <li key={todo.id}>{todo.title}</li>
      ))}
    </ul>
  )
}

With Query Key Variables

function Todo({ todoId }: { todoId: number }) {
  const { data } = useQuery({
    queryKey: ['todo', todoId],
    queryFn: async ({ queryKey }) => {
      const [, id] = queryKey
      const response = await fetch(`/api/todos/${id}`)
      return response.json()
    },
  })

  return <div>{data?.title}</div>
}

Dependent Query

function UserProjects({ userId }: { userId: number | null }) {
  const { data } = useQuery({
    queryKey: ['projects', userId],
    queryFn: ({ queryKey }) => fetchProjects(queryKey[1]),
    enabled: !!userId, // Only run when userId is available
  })

  // ...
}

With Select Transform

const { data } = useQuery({
  queryKey: ['todos'],
  queryFn: fetchTodos,
  select: data => data.filter(todo => todo.completed),
})

With Type Safety

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

const { data } = useQuery<Todo[], Error>({
  queryKey: ['todos'],
  queryFn: fetchTodos,
})
// data is typed as Todo[] | undefined
// error is typed as Error | null

Notes

The query will automatically execute when the component mounts and whenever the queryKey changes, unless enabled is set to false.
If initialData is provided, the query will return status: 'success' immediately and data will be defined.
For queries with suspense: true, use useSuspenseQuery instead for better type safety.

Build docs developers (and LLMs) love