.agents/skills/tanstack-query-expert/SKILL.md
Expert in TanStack Query (React Query) v5 — query key factories, mutations, optimistic updates, cache invalidation, and Next.js App Router SSR hydration. Use when implementing data fetching hooks.
npx skillsauth add sdn0303/terrasight tanstack-query-expertInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Production-grade TanStack Query v5 patterns for this project.
// Global defaults (set in QueryClientProvider)
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 60_000, // 1 minute
gcTime: 300_000, // 5 minutes
retry: 1,
refetchOnWindowFocus: false,
},
},
});
Every feature module MUST define a query key factory:
export const transactionKeys = {
all: ['transactions'] as const,
lists: () => [...transactionKeys.all, 'list'] as const,
list: (filters: TransactionFilters) => [...transactionKeys.lists(), filters] as const,
details: () => [...transactionKeys.all, 'detail'] as const,
detail: (id: string) => [...transactionKeys.details(), id] as const,
};
Always wrap useQuery in custom hooks:
export const useTransactions = (filters: TransactionFilters) => {
return useQuery({
queryKey: transactionKeys.list(filters),
queryFn: () => fetchTransactions(filters),
staleTime: 1000 * 60 * 5,
enabled: !!filters.areaCode,
});
};
export const useCreateTransaction = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: createTransaction,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: transactionKeys.lists() });
},
});
};
export const useUpdateTransaction = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: updateTransaction,
onMutate: async (updated) => {
await queryClient.cancelQueries({ queryKey: transactionKeys.detail(updated.id) });
const previous = queryClient.getQueryData(transactionKeys.detail(updated.id));
queryClient.setQueryData(transactionKeys.detail(updated.id), updated);
return { previous };
},
onError: (_err, _updated, context) => {
queryClient.setQueryData(transactionKeys.detail(context?.previous?.id), context?.previous);
},
onSettled: () => {
queryClient.invalidateQueries({ queryKey: transactionKeys.lists() });
},
});
};
// Server Component (page.tsx)
export default async function TransactionsPage() {
const queryClient = new QueryClient();
await queryClient.prefetchQuery({
queryKey: transactionKeys.list({ areaCode: '13101' }),
queryFn: () => fetchTransactionsServer({ areaCode: '13101' }),
});
return (
<HydrationBoundary state={dehydrate(queryClient)}>
<TransactionsList />
</HydrationBoundary>
);
}
useEffect to fetch data when TanStack Query is availableuseEffect(() => setState(data), [data]))queryFn without custom hook wrapperqueryKey factory — use the factory pattern abovedevelopment
Rust coding rules for Axum/Tokio/SQLx backends in services/backend. 179 rules split into 14 category files covering ownership, error handling, async, API design, and more. Use when writing, reviewing, or refactoring Rust code, designing error types, async flows, or public APIs.
content-media
PostgreSQL and PostGIS patterns for schema design, spatial queries, query optimization, indexing, and zero-downtime migrations. Use when writing SQL, creating tables, optimizing queries, or writing migration files.
development
Mapbox GL JS v3 development patterns for real estate data visualization. Use when working with Mapbox maps, Standard Style configuration, layer slots, 3D lighting, expressions, react-map-gl/mapbox integration, or migrating from MapLibre GL JS.
development
MapLibre GL JS + PostGIS integration patterns for real estate data visualization. Use when working on map layers, spatial queries, GeoJSON data pipelines, or 3D extrusion effects.