apps/app/lib/queries/README.md
This folder contains TanStack Query implementations for managing server state and data fetching in the application.
TanStack Query provides powerful asynchronous state management for TypeScript/JavaScript applications. All query definitions in this folder follow a consistent pattern that enables:
Each query module typically exports:
// user.ts - Example query module structure
import {
queryOptions,
useQuery,
useSuspenseQuery,
} from "@tanstack/react-query";
import type { QueryClient } from "@tanstack/react-query";
// 1. Define query keys with consistent naming
export const userQueryKey = ["users", "detail"] as const;
export const usersListQueryKey = ["users", "list"] as const;
// 2. Create query options factory functions
export function userQueryOptions(userId: string) {
return queryOptions({
queryKey: [...userQueryKey, userId],
queryFn: async () => {
const response = await fetch(`/api/users/${userId}`);
if (!response.ok) throw new Error("Failed to fetch user");
return response.json();
},
staleTime: 5 * 60_000, // Consider data fresh for 5 minutes
gcTime: 10 * 60_000, // Keep in cache for 10 minutes
});
}
// 3. Export convenient hooks
export function useUser(userId: string) {
return useQuery(userQueryOptions(userId));
}
export function useSuspenseUser(userId: string) {
return useSuspenseQuery(userQueryOptions(userId));
}
// 4. Provide utility functions
export async function prefetchUser(queryClient: QueryClient, userId: string) {
return queryClient.prefetchQuery(userQueryOptions(userId));
}
export function invalidateUser(queryClient: QueryClient, userId: string) {
return queryClient.invalidateQueries({
queryKey: [...userQueryKey, userId],
});
}
Query keys should follow a hierarchical structure:
["resource"][("resource", "list")][("resource", "list", { filters })][ // All queries for a resource // List queries // List with filters
("resource", "detail", id)
][("resource", "detail", id, "related")]; // Single item queries // Nested resources
session.tsManages authentication session state with Better Auth integration:
useSuspenseQuery with error boundariesWhen testing components that use queries:
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
const createTestQueryClient = () => new QueryClient({
defaultOptions: {
queries: { retry: false, staleTime: Infinity },
mutations: { retry: false },
},
});
// In your test
const queryClient = createTestQueryClient();
render(
<QueryClientProvider client={queryClient}>
<YourComponent />
</QueryClientProvider>
);