If you ever want to disable a query from automatically running, you can use the enabled = false option. The enabled option also accepts a callback that returns a boolean.
When enabled is false:
TypeScript users may prefer to use skipToken as an alternative to enabled = false.
<script setup>
import { useQuery } from '@tanstack/vue-query'
const { isLoading, isError, data, error, refetch, isFetching } = useQuery({
  queryKey: ['todos'],
  queryFn: fetchTodoList,
  enabled: false,
})
</script>
<template>
  <button @click="refetch()">Fetch Todos</button>
  <span v-if="isLoading">Loading...</span>
  <span v-else-if="isError">Error: {{ error?.message }}</span>
  <div v-else-if="data">
    <span v-if="isFetching">Fetching...</span>
    <ul>
      <li v-for="todo in data" :key="todo.id">{{ todo.title }}</li>
    </ul>
  </div>
  <span v-else>Not ready...</span>
</template>
<script setup>
import { useQuery } from '@tanstack/vue-query'
const { isLoading, isError, data, error, refetch, isFetching } = useQuery({
  queryKey: ['todos'],
  queryFn: fetchTodoList,
  enabled: false,
})
</script>
<template>
  <button @click="refetch()">Fetch Todos</button>
  <span v-if="isLoading">Loading...</span>
  <span v-else-if="isError">Error: {{ error?.message }}</span>
  <div v-else-if="data">
    <span v-if="isFetching">Fetching...</span>
    <ul>
      <li v-for="todo in data" :key="todo.id">{{ todo.title }}</li>
    </ul>
  </div>
  <span v-else>Not ready...</span>
</template>
Permanently disabling a query opts out of many great features that TanStack Query has to offer (like background refetches), and it's also not the idiomatic way. It takes you from the declarative approach (defining dependencies when your query should run) into an imperative mode (fetch whenever I click here). It is also not possible to pass parameters to refetch. Oftentimes, all you want is a lazy query that defers the initial fetch:
The enabled option can not only be used to permanently disable a query, but also to enable / disable it at a later time. A good example would be a filter form where you only want to fire off the first request once the user has entered a filter value:
<script setup>
import { useQuery } from '@tanstack/vue-query'
const filter = ref('')
const isEnabled = computed(() => !!filter.value)
const { data } = useQuery({
  queryKey: ['todos', filter],
  queryFn: () => fetchTodos(filter),
  // ⬇️ disabled as long as the filter is empty
  enabled: isEnabled,
})
</script>
<template>
  <span v-if="data">Filter was set and data is here!</span>
</template>
<script setup>
import { useQuery } from '@tanstack/vue-query'
const filter = ref('')
const isEnabled = computed(() => !!filter.value)
const { data } = useQuery({
  queryKey: ['todos', filter],
  queryFn: () => fetchTodos(filter),
  // ⬇️ disabled as long as the filter is empty
  enabled: isEnabled,
})
</script>
<template>
  <span v-if="data">Filter was set and data is here!</span>
</template>
Lazy queries will be in status: 'pending' right from the start because pending means that there is no data yet. This is technically true, however, since we are not currently fetching any data (as the query is not enabled), it also means you likely cannot use this flag to show a loading spinner.
If you are using disabled or lazy queries, you can use the isLoading flag instead. It's a derived flag that is computed from:
isPending && isFetching
so it will only be true if the query is currently fetching for the first time.
If you are using TypeScript, you can use the skipToken to disable a query. This is useful when you want to disable a query based on a condition, but you still want to keep the query to be type safe.
IMPORTANT: refetch from useQuery will not work with skipToken. Calling refetch() on a query that uses skipToken will result in a Missing queryFn error because there is no valid query function to execute. If you need to manually trigger queries, consider using enabled: false instead, which allows refetch() to work properly. Other than this limitation, skipToken works the same as enabled: false.
<script setup>
import { useQuery, skipToken } from '@tanstack/vue-query'
const filter = ref('')
const queryFn = computed(() =>
  !!filter.value ? () => fetchTodos(filter) : skipToken,
)
const { data } = useQuery({
  queryKey: ['todos', filter],
  // ⬇️ disabled as long as the filter is undefined or empty
  queryFn: queryFn,
})
</script>
<template>
  <span v-if="data">Filter was set and data is here!</span>
</template>
<script setup>
import { useQuery, skipToken } from '@tanstack/vue-query'
const filter = ref('')
const queryFn = computed(() =>
  !!filter.value ? () => fetchTodos(filter) : skipToken,
)
const { data } = useQuery({
  queryKey: ['todos', filter],
  // ⬇️ disabled as long as the filter is undefined or empty
  queryFn: queryFn,
})
</script>
<template>
  <span v-if="data">Filter was set and data is here!</span>
</template>
