All skills
skilld-dev avatar

/tanstack-vue-query-skilld

@b9c39cb

Hooks for managing, caching and syncing asynchronous and remote data in Vue. ALWAYS use when writing code importing "@tanstack/vue-query". Consult for debugging, best practices, or modifying @tanstack/vue-query, tanstack/vue-query, tanstack vue-query, tanstack vue query, query.

Use this Skill: https://skilld.dev/gh/skilld-dev/vue-ecosystem-skills/tanstack-vue-query-skilld

This session only. Nothing lands on disk.

SKILL.md

≈76 tokens always: the name and description. ≈1.4k when used: this file. ≈5.7k more on demand in 5 files.

@tanstack/vue-query@5.103.2

Async data hooks for Vue. Version 5.103.2, prepared source at input/source. Peer deps: vue ^2.6.0 || ^3.3.0; Vue 2 needs @vue/composition-api (optional peer) (package.json:56-59). Re-exports everything from @tanstack/query-core 5.103.2, so keepPreviousData, skipToken, focusManager, onlineManager, hydration utils, and observer classes import from @tanstack/vue-query directly (src/index.ts:1).

Setup

Install the plugin once per app. It creates (or accepts) a QueryClient, provides it app-wide, and mounts/unmounts it (src/vueQueryPlugin.ts:74-154):

import { createApp } from 'vue'
import { QueryClient, VueQueryPlugin } from '@tanstack/vue-query'

const app = createApp(App)

// Option A: pass your own client (required for SSR — one fresh client per request)
const queryClient = new QueryClient()
app.use(VueQueryPlugin, { queryClient })

// Option B: let the plugin build one with your defaults
app.use(VueQueryPlugin, {
  queryClientConfig: { defaultOptions: { queries: { staleTime: 5 * 1000 } } },
})

VueQueryPluginOptions: queryClient or queryClientConfig (one or the other), queryClientKey (only when installing multiple clients), clientPersister + clientPersisterOnSuccess (persisted cache restore), enableDevtoolsV6Plugin (src/vueQueryPlugin.ts:11-38). The client is not mounted on the server (src/vueQueryPlugin.ts:87-89).

useQueryClient(id?) throws outside an injection context or without the plugin (src/useQueryClient.ts:27-44).

Basic query

<script setup lang="ts">
import { ref } from 'vue'
import { useQuery } from '@tanstack/vue-query'

const postId = ref(1)
const { status, data, error, refetch } = useQuery({
  queryKey: ['post', postId],          // ref inside the key: tracked, no .value
  queryFn: () => fetchPost(postId.value),
})
</script>

<template>
  <span v-if="status === 'pending'">Loading...</span>
  <span v-else-if="status === 'error'">Error: {{ error!.message }}</span>
  <h1 v-else>{{ data!.title }}</h1>
</template>

Basic mutation

<script setup lang="ts">
import { useMutation, useQueryClient } from '@tanstack/vue-query'

const queryClient = useQueryClient()
const addMutation = useMutation({
  mutationFn: addTodo,
  onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
})

function onAdd() {
  addMutation.mutate('Item', {
    onError: (error) => console.error('Failed:', error),
  })
}
</script>

<template>
  <button @click="onAdd">Add</button>
</template>

mutate swallows rejection by design; per-call callbacks fire only for the latest call. Use mutateAsync for a promise per call (src/useMutation.ts:262-270).

Rules that catch Vue developers

  • Returns are Refs. Every result field of useQuery/useInfiniteQuery/useMutation is a Ref (data.value in script, auto-unwrapped in template), except the functions refetch, fetchNextPage, fetchPreviousPage, mutate, mutateAsync, reset, plus suspense() (src/useBaseQuery.ts:27-40, src/useMutation.ts:53-68).
  • useQueries returns one Ref of the whole result array (or the combine value), not a reactive array (src/useQueries.ts:357-376).
  • Never unwrap refs for the query key. Put the ref itself into queryKey and read .value inside queryFn (src/utils.ts:84-111).
  • Only queryKey and enabled accept reactive getters. A function anywhere else is the real callback (queryFn, select, ...). To make any option reactive, pass a whole-options getter useQuery(() => ({ ... })) (src/queryOptions.ts:67-76, src/useQuery.ts:225-227).
  • initialData is not reactive; it is read once (src/queryOptions.ts:136-148).
  • Call composables in setup() or an effectScope. Outside a scope, dev mode warns about memory leaks (src/useBaseQuery.ts:82-88).
  • Imperative fetches go through queryClient.query() / queryClient.infiniteQuery(). fetchQuery, prefetchQuery, fetchInfiniteQuery, prefetchInfiniteQuery, ensureQueryData are deprecated and slated for removal (src/queryClient.ts:251-253, src/queryClient.ts:311-313).
  • Declare shared queries with queryOptions() so the key carries its data type for getQueryData, invalidateQueries, and prefetch reuse (src/queryOptions.ts:244-251).

Environment limits

  • Prepared source: @tanstack/vue-query 5.103.2 with @tanstack/query-core 5.103.2 (package.json:2,45). Docs match v5; v4 APIs may appear in old examples.
  • Vue 3.3+ for Vue 3; Vue 2.6+ with @vue/composition-api, or Vue 2.7 native (package.json:52-59).
  • ESM-first dual build (build/modern, build/legacy); sideEffects: false (package.json:21-35).

References

Official docs: https://tanstack.com/query/latest/docs/framework/vue/overview

Source: SKILL.md on GitHub

No alerts8d3 checks · Risk SAFE
  • Gen Agent Trust Hub8d

    This skill provides comprehensive documentation, best practices, and API references for the TanStack Vue Query library (@tanstack/vue-query). No security issues or malicious patterns were detected; the skill consists entirely of knowledge-base content intended to help an AI agent assist with Vue Query development.

  • Socket8d

    No alerts

  • Snyk8d

    Risk: LOW · No issues

Signed by skilld at b9c39cb. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub last week.

Activeupdated last week

README badge

README badge for skilld-dev/vue-ecosystem-skills/tanstack-vue-query-skilld