This episode covers the TanStack Query framework adapter ecosystem: Vue Query, Svelte Query, Solid Query, and Preact Query, all sharing the same engine, @tanstack/query-core, as well as using QueryClient outside a framework for Node services and event handlers.

For eighteen episodes, you've only met one face of TanStack Query: React Query. Behind that familiar useQuery hook there turns out to be one framework-agnostic engine named @tanstack/query-core. This engine is what hosts QueryClient, the cache, observers, and all the retry, deduplication, and structural sharing logic you've learned.
Episode 19 opens the adapter ecosystem chest: Vue Query, Svelte Query, Solid Query, and Preact Query. You'll see that all the adapters use exactly the same concepts — what changes is only each framework's reactivity idiom. In the second half, you learn to use QueryClient directly outside a framework for Node services, event handlers, and batch scripts.
Vue Query offers composables with the same names as the React hooks: useQuery, useMutation, and useInfiniteQuery. Vue Query uses QueryClientProvider to inject the client into the whole application, and useQuery inside a <script setup> component works reactively:
npm i @tanstack/vue-query
npm i @tanstack/svelte-query
npm i @tanstack/solid-query
npm i @tanstack/preact-query<script setup lang="ts">
import { useQuery } from "@tanstack/vue-query"
async function fetchTodos() {
const res = await fetch("https://jsonplaceholder.typicode.com/todos")
if (!res.ok) throw new Error("Gagal mengambil todos")
return res.json()
}
const { data, isPending, isError } = useQuery({
queryKey: ["todos"],
queryFn: fetchTodos,
})
</script>Notice that queryKey, queryFn, and isPending are identical to React. useQuery in Vue returns reactive refs that can be used directly in templates. The knowledge from episodes 3 through 18 transfers almost without changing concepts.
Svelte Query presents primitives aligned with Svelte idioms: createQuery, createMutation, and createInfiniteQuery. The create name is used because Svelte is more familiar with stores and functions than hooks. The concepts of query keys, staleTime, and invalidation still run on the same core:
<script lang="ts">
import { createQuery } from "@tanstack/svelte-query"
import { client } from "../lib/query-client"
const query = createQuery({
queryKey: ["todos"],
queryFn: fetchTodos,
})
</script>
{#if $query.isPending}
<p>Memuat data...</p>
{:else if $query.isError}
<p>Terjadi error: {$query.error.message}</p>
{:else}
<ul>
{#each $query.data as todo}
<li>{todo.title}</li>
{/each}
</ul>
{/if}createQuery returns a Svelte store read with the dollar prefix. $query.data and $query.isPending work exactly like data and isPending in React, because both are just projections of the same cache state.
Solid Query uses Solid's reactivity primitives: createQuery with signals, suited for Solid applications with granular performance. Preact Query ships as @tanstack/preact-query with an API almost identical to React Query, so teams using Preact don't need to relearn anything.
These four adapters, plus Angular (still experimental) and Lit, are managed in a single TanStack/query monorepo. They don't duplicate logic: they're all thin layers on top of @tanstack/query-core, which speaks about observers, cache, and query state.
The adapter ecosystem only makes sense because the core is framework-agnostic. The @tanstack/query-core package doesn't depend on React, Vue, Svelte, or Solid — it only deals with pure JavaScript and TypeScript. This is why @tanstack/query-core can be used anywhere, including in Node.
The adapter dependency structure is clearly visible from the package manifest. Each adapter declares the core as a dependency:
{
"name": "@tanstack/react-query",
"dependencies": {
"@tanstack/query-core": "5.101.2"
}
}The consequence is interesting: when you understand how the cache works in React, that understanding applies in Vue, Svelte, and Solid. retry, gcTime, invalidateQueries, and structural sharing are core behaviors — not React features. Adapters only translate state observation into each framework's render mechanism.
Because the core doesn't care about frameworks, QueryClient can be instantiated and used outside the UI. This is useful for Node services that want to benefit from caching, deduplication, and retry without rewriting that logic:
import { QueryClient } from "@tanstack/query-core"
export const client = new QueryClient({
defaultOptions: {
queries: {
staleTime: 60 * 1000,
retry: 2,
},
},
})
export async function loadTodos() {
return client.fetchQuery({
queryKey: ["todos"],
queryFn: () =>
fetch("https://jsonplaceholder.typicode.com/todos").then((res) => {
if (!res.ok) throw new Error("Gagal mengambil todos")
return res.json()
}),
})
}fetchQuery is the imperative version of useQuery: it directly fetches data, fills it into the cache, and returns a Promise. Two processes calling loadTodos simultaneously won't duplicate the fetch — deduplication in the core works without needing observers from any framework.
Caching is also useful outside UI requests. For example, a queue handler that needs to mark data as stale after an event message arrives, or a batch script that uses the cache to avoid repeated API calls:
import { client } from "./query-client"
export async function handleTodoCreated(event) {
await client.invalidateQueries({ queryKey: ["todos"] })
console.log("Cache todos ditandai basi setelah:", event.title)
}This pattern is very valuable in realtime architectures: when a webhook or message broker notifies that data has changed, a single invalidateQueries call can mark all relevant caches as stale. Active UIs will automatically refetch — cross-process synchronization without manual code.
Episode 19 broadened your horizons: TanStack Query isn't a React library, but a server state engine with adapters for React, Vue, Svelte, Solid, and Preact. The framework-agnostic @tanstack/query-core can be used directly in Node, event handlers, and scripts.
Key takeaways:
@tanstack/query-core engine.useQuery in React is equivalent to useQuery in Vue and createQuery in Svelte.staleTime, and invalidation apply across frameworks.QueryClient can be used in Node without any framework.fetchQuery is the imperative version of useQuery.invalidateQueries from an event handler syncs the UI automatically.In the next episode, episode 20, we will discuss the latest stable features of v5.x — the keyed-object API, useSuspenseQuery, structural sharing, default retry, React 19 support, up to the v5.101.x release in July 2026 and the direction toward Query v6.