tanstack-query
Manage data fetching and caching in Svelte apps.
Install
mkdir -p .claude/skills/tanstack-query && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/1100" && unzip -o skill.zip -d .claude/skills/tanstack-query && rm skill.zipInstalls to .claude/skills/tanstack-query
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Use this skill when fetching data, managing server state, or handling API mutations in the Svelte frontend. Covers createQuery, createMutation, query keys, cache invalidation, optimistic updates, and WebSocket-driven refetching. Apply when adding API calls, managing loading/error states, or coordinating cache updates after mutations.Key capabilities
- →Implement query keys for consistent cache management
- →Execute mutations with automatic cache invalidation
- →Perform optimistic UI updates for responsiveness
- →Sync state using WebSocket-driven invalidation
- →Manage dependent queries with enabled conditions
How it works
It centralizes API logic into feature-specific files, using query key factories to ensure cache consistency across queries and mutations.
Inputs & outputs
When to use tanstack-query
- →Setup query keys and cache invalidation
- →Implement optimistic UI updates
- →Manage WebSocket-driven data synchronization
About this skill
TanStack Query
Documentation: tanstack.com/query. Use official docs when the local pattern is not enough.
Centralize API calls in api.svelte.ts per feature using TanStack Query with @exceptionless/fetchclient.
Query Basics
// src/lib/features/organizations/api.svelte.ts
import { createQuery, createMutation, useQueryClient } from "@tanstack/svelte-query";
import { type FetchClientResponse, type ProblemDetails, useFetchClient } from "@exceptionless/fetchclient";
import { accessToken } from "$features/auth/index.svelte";
const queryKeys = {
type: ["Organization"] as const,
};
export function getOrganizationsQuery() {
return createQuery<FetchClientResponse<Organization[]>, ProblemDetails>(() => ({
enabled: () => !!accessToken.current,
queryKey: queryKeys.type,
queryFn: async ({ signal }: { signal: AbortSignal }) => {
const client = useFetchClient();
const response = await client.getJSON<Organization[]>("/organizations", { signal });
return response;
},
}));
}
Query Keys Convention
Use a queryKeys factory per feature for type safety and consistency:
export const queryKeys = {
type: ["Webhook"] as const,
id: (id: string | undefined) => [...queryKeys.type, id] as const,
ids: (ids: string[] | undefined) => [...queryKeys.type, ...(ids ?? [])] as const,
project: (id: string | undefined) => [...queryKeys.type, "project", id] as const,
deleteWebhook: (ids: string[] | undefined) => [...queryKeys.ids(ids), "delete"] as const,
postWebhook: () => [...queryKeys.type, "post"] as const,
};
Prefer the feature's queryKeys factory over ad-hoc arrays so WebSocket invalidation and cache updates share the same keys.
Mutations
export function postOrganizationMutation() {
const queryClient = useQueryClient();
return createMutation(() => ({
mutationFn: async (data: CreateOrganizationRequest) => {
const client = useFetchClient();
const response = await client.postJSON<Organization>("/organizations", data);
return response.data!;
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: queryKeys.type });
},
}));
}
Naming Conventions
| Pattern | Naming | Example |
|---|---|---|
| Query (GET) | get{Resource}Query | getOrganizationsQuery() |
| Create (POST) | post{Resource}Mutation | postOrganizationMutation() |
| Update (PATCH) | patch{Resource}Mutation | patchOrganizationMutation() |
| Delete (DELETE) | delete{Resource}Mutation | deleteOrganizationMutation() |
Dependent Queries
Use enabled to conditionally run queries: enabled: !!projectId.
Optimistic Updates
For mutations that update cached data optimistically: use onMutate to cancel in-flight queries, snapshot previous value via getQueryData, and apply optimistic update via setQueryData. Use onError to rollback from snapshot, and onSettled to always invalidateQueries for the final refetch.
WebSocket-Driven Invalidation
Invalidate queries when WebSocket messages arrive:
export async function invalidateWebhookQueries(
queryClient: QueryClient,
message: WebSocketMessageValue<"WebhookChanged">,
) {
const { id, organization_id, project_id } = message;
if (id) await queryClient.invalidateQueries({ queryKey: queryKeys.id(id) });
if (project_id) await queryClient.invalidateQueries({ queryKey: queryKeys.project(project_id) });
if (!id && !organization_id && !project_id)
await queryClient.invalidateQueries({ queryKey: queryKeys.type });
}
Wire WebSocket messages from the app layout to the feature invalidation helper.
When not to use it
- →When simple fetch calls are sufficient
- →When state is purely local and non-server-driven
Prerequisites
Limitations
- →Requires consistent use of query key factories
How it compares
It provides a structured, type-safe way to handle server state and cache synchronization compared to manual fetch management.
Compared to similar skills
tanstack-query side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| tanstack-query (this skill) | 7 | 2mo | No flags | Intermediate |
| svelte-migrate | 2 | 7mo | No flags | Intermediate |
| shopify-development | 12 | 6mo | Review | Intermediate |
| nuxt | 19 | 6mo | No flags | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by exceptionless
View all by exceptionless →You might also like
svelte-migrate
temporalio
Migrate a Svelte 4 component to Svelte 5 runes syntax. Use when asked to migrate, convert, or upgrade a .svelte file to Svelte 5.
shopify-development
davila7
Build Shopify apps, extensions, themes using GraphQL Admin API, Shopify CLI, Polaris UI, and Liquid. TRIGGER: "shopify", "shopify app", "checkout extension", "admin extension", "POS extension", "shopify theme", "liquid template", "polaris", "shopify graphql", "shopify webhook", "shopify billing", "app subscription", "metafields", "shopify functions"
nuxt
antfu
Nuxt full-stack Vue framework with SSR, auto-imports, and file-based routing. Use when working with Nuxt apps, server routes, useFetch, middleware, or hybrid rendering.
telegram-dev
2025Emma
Telegram 生态开发全栈指南 - 涵盖 Bot API、Mini Apps (Web Apps)、MTProto 客户端开发。包括消息处理、支付、内联模式、Webhook、认证、存储、传感器 API 等完整开发资源。
yjs
EpicenterHQ
Yjs CRDT patterns, shared types, conflict resolution, and meta data structures. Use when building collaborative apps with Yjs, handling Y.Map/Y.Array/Y.Text, implementing drag-and-drop reordering, or optimizing document storage.
bun-development
davila7
Modern JavaScript/TypeScript development with Bun runtime. Covers package management, bundling, testing, and migration from Node.js. Use when working with Bun, optimizing JS/TS development speed, or migrating from Node.js to Bun.