Load independent dashboard data in parallel
A dashboard needs independent users, teams, and metrics before rendering.
TanStack · Hook
useSuspenseQueries runs multiple TanStack Query requests concurrently under React Suspense. It returns their results or an optional combined value, with each query's data guaranteed to be defined.
The hook accepts an array of query configurations and optionally a combine function. It suspends while required data loads, runs the queries in parallel, and returns a combined value or the usual query-result structure with defined data for every query.
function useSuspenseQueries<T, TCombinedResult>(options: object, queryClient?: QueryClient): TCombinedResult;| Name | Type | Description |
|---|---|---|
options | object | Configuration object containing the queries array and optional combine function; each query follows useQueries options with the documented exclusions. |
queryClient | QueryClient | Optional QueryClient used by the hook. |
TCombinedResult; without combine, the result has the useQueries structure, with defined data, no isPlaceholderData, and status limited to success or error.
import { useSuspenseQueries } from '@tanstack/react-query'
async function fetchJson<T>(url: string): Promise<T> {
const response = await fetch(url)
if (!response.ok) throw new Error(`HTTP ${response.status}`)
return response.json() as Promise<T>
}
export function Dashboard() {
const [users, teams] = useSuspenseQueries({
queries: [
{ queryKey: ['users'], queryFn: () => fetchJson<string[]>('/api/users') },
{ queryKey: ['teams'], queryFn: () => fetchJson<string[]>('/api/teams') },
],
combine: (results) => ({ users: results[0], teams: results[1] }),
})
return <p>{users.length} users in {teams.length} teams</p>
}Runs both requests through Suspense and combines their results into one value.
A dashboard needs independent users, teams, and metrics before rendering.
Several suspenseful queries belong to one component and should not create a waterfall.
A component wants a domain-specific object instead of an array of query results.
It is the Suspense-oriented multi-query hook. It receives a queries array, starts those queries in parallel, and can transform their results with combine; unlike separate suspense hooks, it avoids serial suspension.
Follow-up: Why not call multiple useSuspenseQuery hooks? Each can suspend before later hooks start, creating a request waterfall; useSuspenseQueries coordinates them together.
Its options follow useQueries, with two differences: top-level subscribed is unsupported, and each query cannot set throwOnError, enabled, or placeholderData. The hook's signature also accepts an optional QueryClient.
Follow-up: How would a component conditionally skip one query? Suspense query configuration cannot use enabled, so restructure the component or query set rather than disabling an individual entry.
Without combine, the return has the same overall structure as useQueries, but every query's data is guaranteed to be defined. isPlaceholderData is absent, and status is limited to success or error with corresponding derived flags.
Follow-up: What should handle errors? Use the surrounding Suspense and error-boundary model rather than relying on an enabled or placeholderData escape hatch.
useQueriesuseSuspenseQueryuseSuspenseInfiniteQueryusePrefetchQueryQueryClient