Skip to content

Query Keys & Options

To simplify query key management and improve maintainability, it’s recommended to use Query Key Factories for each feature.

// src/features/posts/api/queryKeys
export const postKeys = {
all: () => ["posts"] as const,
lists: () => [...postKeys.all(), "list"] as const,
list: (filter: PostListFilter) => [...postKeys.lists(), filter] as const,
details: () => [...postKeys.all(), "detail"] as const,
detail: (id: number) => [...postKeys.details(), id],
};

We encourage the usage of queryOptions instead of using a custom hook that wraps useQuery.
It’s a much more flexible solution because this way it’s possible to use it in many different scenarios:

const { data, isPending, isError, error } = useQuery(
postDetailQueryOptions(id),
);

In a component with a suspense boundary using useSuspenseQuery

Section titled “In a component with a suspense boundary using useSuspenseQuery”
const { data } = useSuspenseQuery(postDetailQueryOptions(id));

In a Tanstack router route loader with queryClient methods

Section titled “In a Tanstack router route loader with queryClient methods”
export const Route = createFileRoute("/_Layout/posts_/$postId")({
loader: async ({ context: { queryClient }, params: { postId } }) => {
await queryClient.ensureQueryData(postDetailQueryOptions(postId));
},
component: RouteComponent,
});

We won’t be able to achieve this flexibility with doing something like usePostDetail() custom hook that is just a wrapper around useQuery with hardcoded options.