useQueries composable. It returns an array of query results that are all reactive and managed independently.
Signature
function useQueries<T extends Array<any>, TCombinedResult>(
options: {
queries: UseQueriesOptionsArg<T> | (() => UseQueriesOptionsArg<T>)
combine?: (results: UseQueriesResults<T>) => TCombinedResult
} & ShallowOption,
queryClient?: QueryClient,
): Readonly<Ref<TCombinedResult>>
Parameters
Configuration object for multiple queries.
Show properties
Show properties
Array of query options or a function that returns the array. Each element can be reactive.
Optional function to combine/transform the results array into a custom structure.
Return data in a shallow ref (improves performance if data doesn’t need deep reactivity).
Custom QueryClient instance. If not provided, uses the client from context.
Returns
Reactive ref containing array of query results (or combined result if
combine is provided).When not using combine, each element contains:Show properties
Show properties
The query result data.
The error object if the query failed.
true when fetching for the first time.true whenever the query is fetching.true when the query has successfully fetched data.true when the query encountered an error.The current status of the query.
Manually trigger a refetch of this specific query.
Type Parameters
T- Tuple type representing the array of query optionsTCombinedResult- Type of combined result (defaults toUseQueriesResults<T>)
Examples
Basic Usage
<script setup>
import { ref } from 'vue'
import { useQueries } from '@tanstack/vue-query'
const userIds = ref([1, 2, 3])
const results = useQueries({
queries: userIds.value.map((id) => ({
queryKey: ['user', id],
queryFn: () => fetchUser(id),
})),
})
// results.value is an array of query results
</script>
<template>
<div>
<div v-for="(result, index) in results" :key="index">
<div v-if="result.isLoading">Loading user {{ index + 1 }}...</div>
<div v-else-if="result.error">Error: {{ result.error.message }}</div>
<div v-else>{{ result.data?.name }}</div>
</div>
</div>
</template>
With TypeScript
<script setup lang="ts">
import { useQueries } from '@tanstack/vue-query'
interface User {
id: number
name: string
email: string
}
interface Post {
id: number
title: string
userId: number
}
const results = useQueries({
queries: [
{
queryKey: ['user', 1],
queryFn: async (): Promise<User> => {
const res = await fetch('/api/users/1')
return res.json()
},
},
{
queryKey: ['posts'],
queryFn: async (): Promise<Post[]> => {
const res = await fetch('/api/posts')
return res.json()
},
},
],
})
// results.value[0].data is typed as User | undefined
// results.value[1].data is typed as Post[] | undefined
</script>
Dynamic Queries
<script setup>
import { ref, computed } from 'vue'
import { useQueries } from '@tanstack/vue-query'
const userIds = ref([1, 2, 3])
// Use a function to make queries reactive
const results = useQueries({
queries: () => userIds.value.map((id) => ({
queryKey: ['user', id],
queryFn: () => fetchUser(id),
})),
})
const addUser = () => {
userIds.value.push(userIds.value.length + 1)
// Automatically triggers new query for the new user
}
</script>
Combining Results
<script setup>
import { useQueries } from '@tanstack/vue-query'
const combinedData = useQueries({
queries: [
{ queryKey: ['users'], queryFn: fetchUsers },
{ queryKey: ['posts'], queryFn: fetchPosts },
{ queryKey: ['comments'], queryFn: fetchComments },
],
combine: (results) => {
return {
users: results[0].data,
posts: results[1].data,
comments: results[2].data,
isLoading: results.some(r => r.isLoading),
isError: results.some(r => r.isError),
}
},
})
// combinedData.value has the structure defined in combine function
</script>
<template>
<div>
<div v-if="combinedData.isLoading">Loading...</div>
<div v-else-if="combinedData.isError">Error occurred</div>
<div v-else>
<p>Users: {{ combinedData.users?.length }}</p>
<p>Posts: {{ combinedData.posts?.length }}</p>
<p>Comments: {{ combinedData.comments?.length }}</p>
</div>
</div>
</template>
Conditional Queries
<script setup>
import { ref } from 'vue'
import { useQueries } from '@tanstack/vue-query'
const userIds = ref([1, 2, 3])
const enabled = ref(true)
const results = useQueries({
queries: () => userIds.value.map((id) => ({
queryKey: ['user', id],
queryFn: () => fetchUser(id),
enabled: enabled.value, // All queries controlled by same flag
})),
})
</script>
Different Query Options
<script setup>
import { useQueries } from '@tanstack/vue-query'
const results = useQueries({
queries: [
{
queryKey: ['critical-data'],
queryFn: fetchCriticalData,
staleTime: 0, // Always fresh
refetchOnWindowFocus: true,
},
{
queryKey: ['cached-data'],
queryFn: fetchCachedData,
staleTime: 1000 * 60 * 5, // 5 minutes
gcTime: 1000 * 60 * 10, // 10 minutes
},
{
queryKey: ['background-data'],
queryFn: fetchBackgroundData,
refetchInterval: 30000, // Refetch every 30 seconds
},
],
})
</script>
Accessing Individual Results
<script setup>
import { computed } from 'vue'
import { useQueries } from '@tanstack/vue-query'
const results = useQueries({
queries: [
{ queryKey: ['user'], queryFn: fetchUser },
{ queryKey: ['posts'], queryFn: fetchPosts },
],
})
// Extract individual results
const userQuery = computed(() => results.value[0])
const postsQuery = computed(() => results.value[1])
// Check if all queries are loaded
const allLoaded = computed(() =>
results.value.every(r => r.isSuccess)
)
// Check if any query is loading
const anyLoading = computed(() =>
results.value.some(r => r.isLoading)
)
</script>
Refetch Individual Queries
<script setup>
import { useQueries } from '@tanstack/vue-query'
const results = useQueries({
queries: [
{ queryKey: ['user'], queryFn: fetchUser },
{ queryKey: ['posts'], queryFn: fetchPosts },
],
})
const refetchUser = () => {
results.value[0].refetch()
}
const refetchAll = () => {
results.value.forEach(result => result.refetch())
}
</script>
Type-Safe Queries Array
<script setup lang="ts">
import { useQueries } from '@tanstack/vue-query'
interface User {
id: number
name: string
}
interface Post {
id: number
title: string
}
// Explicitly type the queries array
const results = useQueries({
queries: [
{
queryKey: ['user'] as const,
queryFn: async (): Promise<User> => {
const res = await fetch('/api/user')
return res.json()
},
},
{
queryKey: ['posts'] as const,
queryFn: async (): Promise<Post[]> => {
const res = await fetch('/api/posts')
return res.json()
},
},
] as const,
})
// Full type inference for each result
</script>
Notes
Each query in the array is tracked independently. Changing one query’s parameters will only refetch that specific query.
Use the
combine option to derive custom data structures from the results array, such as aggregating loading states or merging data.When using a function for the
queries option, make sure it’s reactive (uses Vue refs/computed). Static arrays won’t react to changes.Related
- useQuery - For single queries
- Query Keys Guide - Best practices for query keys