Opinionated TanStack Query v5

Your API schema is the source of truth

use-q is an opinionated way to use TanStack Query: one schema becomes typed hooks, hierarchical query keys, and automatic invalidation — TkDodo's Practical React Query patterns, without giving up Query itself.

pnpm add @use-q/api-client-react @tanstack/react-query

Define once, use everywhere

Describe each route's method, path, params, body, response, and cache tags in a single place. Every hook, query key, and invalidation is derived from it.

api/client.ts
const schema = {
  listPosts: {
    method: "GET",
    path: "/facilities/{facilityId}/posts",
    tags: ["posts"],
  } satisfies RouteDefinition<
    { facilityId: string }, // path params
    { search?: string },    // search params
    never,                  // body
    Post[]                  // response
  >,
  createPost: {
    method: "POST",
    path: "/facilities/{facilityId}/posts",
    invalidatesTags: ["posts"],
  } satisfies RouteDefinition<{ facilityId: string }, never, { title: string }, Post>,
} as const;

export const api = createApiClient(schema, {
  baseUrl: "https://api.example.com",
});
PostList.tsx
function PostList({ facilityId }: { facilityId: string }) {
  // data is Post[] — inferred, not asserted
  const { data } = api.useQ("listPosts", { params: { facilityId } });
  const createPost = api.useM("createPost");

  // listPosts refetches automatically after this succeeds
  return (
    <button
      onClick={() =>
        createPost.mutate({ params: { facilityId }, body: { title: "Hi" } })
      }
    />
  );
}

Ready to dive in?

Install the packages, define your first schema, and ship a typed list-and-create flow in five minutes.

Read the docs