Skip to content
tRPC

Partners

TanStack React Query

Set up the TanStack React Query integration with or without React context, then query, mutate and invalidate

On this page

Compared to our classic React Query Integration this client is simpler and more TanStack Query-native, providing factories for common TanStack React Query interfaces like QueryKeys, QueryOptions, and MutationOptions. We think it's the future and recommend using this over the classic client, read the announcement post for more information about this change.

❓ Do I have to use an integration?

No! The integration is fully optional. You can use @tanstack/react-query using just a vanilla tRPC client, although then you'll have to manually manage query keys and do not get the same level of DX as when using the integration package.

utils/trpc.ts
import { function createTRPCClient<TRouter extends AnyRouter>(opts: CreateTRPCClientOptions<TRouter>): TRPCClient<TRouter>createTRPCClient, function httpBatchLink<TRouter extends AnyRouter>(opts: HTTPBatchLinkOptions<TRouter["_def"]["_config"]["$types"]>): TRPCLink<TRouter>httpBatchLink } from '@trpc/client';
import type { 
type AppRouter = Router<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        list: QueryProcedure<{
            input: void;
            output: {
                id: string;
                title: string;
            }[];
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
    }>>;
}>> & DecorateCreateRouterOptions<{
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        list: QueryProcedure<{
            input: void;
            output: {
                id: string;
                title: string;
            }[];
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
    }>>;
}>
AppRouter
} from '../server/router';
export const
const trpc: TRPCClient<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        list: QueryProcedure<{
            input: void;
            output: {
                id: string;
                title: string;
            }[];
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
    }>>;
}>>>
trpc
=
createTRPCClient<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        list: QueryProcedure<{
            input: void;
            output: {
                id: string;
                title: string;
            }[];
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
    }>>;
}>>>(opts: CreateTRPCClientOptions<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<...>>>): TRPCClient<...>
createTRPCClient
<
type AppRouter = Router<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        list: QueryProcedure<{
            input: void;
            output: {
                id: string;
                title: string;
            }[];
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
    }>>;
}>> & DecorateCreateRouterOptions<{
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        list: QueryProcedure<{
            input: void;
            output: {
                id: string;
                title: string;
            }[];
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
    }>>;
}>
AppRouter
>({
links: TRPCLink<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        list: QueryProcedure<{
            input: void;
            output: {
                id: string;
                title: string;
            }[];
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
    }>>;
}>>>[]
links
: [
httpBatchLink<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        list: QueryProcedure<{
            input: void;
            output: {
                id: string;
                title: string;
            }[];
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
    }>>;
}>>>(opts: HTTPBatchLinkOptions<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}>): TRPCLink<...>
httpBatchLink
({ url: string | URLurl: 'YOUR_API_URL' })],
});
components/PostList.tsx
import { function useQuery<TQueryFnData = unknown, TError = Error, TData = TQueryFnData, TQueryKey extends QueryKey = readonly unknown[]>(options: DefinedInitialDataOptions<TQueryFnData, TError, TData, TQueryKey>, queryClient?: QueryClient): DefinedUseQueryResult<TData, TError> (+2 overloads)useQuery } from '@tanstack/react-query';
import { 
const trpc: TRPCClient<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        list: QueryProcedure<{
            input: void;
            output: {
                id: string;
                title: string;
            }[];
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
    }>>;
}>>>
trpc
} from './utils/trpc';
function function PostList(): voidPostList() { const {
const data: {
    id: string;
    title: string;
}[] | undefined
data
} =
useQuery<{
    id: string;
    title: string;
}[], Error, {
    id: string;
    title: string;
}[], readonly ["posts"]>(options: UndefinedInitialDataOptions<{
    id: string;
    title: string;
}[], Error, {
    id: string;
    title: string;
}[], readonly ["posts"]>, queryClient?: QueryClient): UseQueryResult<{
    id: string;
    title: string;
}[], Error> (+2 overloads)
useQuery
({
queryKey: readonly ["posts"]queryKey: ['posts'] as type const = readonly ["posts"]const,
queryFn?: unique symbol | QueryFunction<{
    id: string;
    title: string;
}[], readonly ["posts"], never> | undefined
queryFn
: () =>
const trpc: TRPCClient<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        list: QueryProcedure<{
            input: void;
            output: {
                id: string;
                title: string;
            }[];
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
    }>>;
}>>>
trpc
.
post: DecoratedProcedureRecord<{
    transformer: false;
    errorShape: DefaultErrorShape;
}, DecorateCreateRouterOptions<{
    list: QueryProcedure<{
        input: void;
        output: {
            id: string;
            title: string;
        }[];
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>
post
.
list: {
    query: Resolver<{
        input: void;
        output: {
            id: string;
            title: string;
        }[];
        errorShape: DefaultErrorShape;
        transformer: false;
    }>;
}
list
.
query: (input: void, opts?: TRPCProcedureOptions) => TRPCTaggedPromise<{
    id: string;
    title: string;
}[], DefaultErrorShape>
query
(),
});
const data: {
    id: string;
    title: string;
}[] | undefined
data
; // Post[]
// ... }

Setup

1. Install dependencies

The following dependencies should be installed

pnpm add @trpc/server @trpc/client @trpc/tanstack-react-query @tanstack/react-query
npm install @trpc/server @trpc/client @trpc/tanstack-react-query @tanstack/react-query
yarn add @trpc/server @trpc/client @trpc/tanstack-react-query @tanstack/react-query
bun add @trpc/server @trpc/client @trpc/tanstack-react-query @tanstack/react-query

2. Import your AppRouter

Import your AppRouter type into the client application. This type holds the shape of your entire API.

utils/trpc.ts
import type { 
type AppRouter = Router<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        byId: QueryProcedure<{
            input: {
                id: string;
            };
            output: {
                id: string;
                title: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
    }>>;
}>> & DecorateCreateRouterOptions<{
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        byId: QueryProcedure<{
            input: {
                id: string;
            };
            output: {
                id: string;
                title: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
    }>>;
}>
AppRouter
} from '../server/router';

3a. Set up the tRPC context provider

In cases where you rely on React context, such as when using server-side rendering in full-stack frameworks like Next.js, it's important to create a new QueryClient for each request so that your users don't end up sharing the same cache, you can use the createTRPCContext to create a set of type-safe context providers and consumers from your AppRouter type signature.

utils/trpc.ts
import { 
function createTRPCContext<TRouter extends AnyRouter, TFeatureFlags extends FeatureFlags = {
    keyPrefix: false;
}>(): CreateTRPCContextResult<TRouter, TFeatureFlags>
createTRPCContext
} from '@trpc/tanstack-react-query';
import type {
type AppRouter = Router<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>> & DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>
AppRouter
} from '../server/router';
export const {
const TRPCProvider: TRPCProviderType<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>, {
    keyPrefix: false;
}>
TRPCProvider
,
const useTRPC: () => TRPCOptionsProxy<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>, {
    keyPrefix: false;
}>
useTRPC
,
const useTRPCClient: () => TRPCClient<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>>
useTRPCClient
} =
createTRPCContext<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>, {
    keyPrefix: false;
}>(): CreateTRPCContextResult<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<...>>, {
    keyPrefix: false;
}>
createTRPCContext
<
type AppRouter = Router<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>> & DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>
AppRouter
>();

Then, create a tRPC client, and wrap your application in the TRPCProvider, as below. You will also need to set up and connect React Query, which they document in more depth.

components/App.tsx
import { class QueryClientQueryClient, const QueryClientProvider: ({ client, children }: QueryClientProviderProps) => React.JSX.ElementQueryClientProvider } from '@tanstack/react-query';
import { function createTRPCClient<TRouter extends AnyRouter>(opts: CreateTRPCClientOptions<TRouter>): TRPCClient<TRouter>createTRPCClient, function httpBatchLink<TRouter extends AnyRouter>(opts: HTTPBatchLinkOptions<TRouter["_def"]["_config"]["$types"]>): TRPCLink<TRouter>httpBatchLink } from '@trpc/client';
import { function useState<S>(initialState: S | (() => S)): [S, React.Dispatch<React.SetStateAction<S>>] (+1 overload)useState } from 'react';
import type { 
type AppRouter = Router<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>> & DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>
AppRouter
} from '../server/router';
import {
const TRPCProvider: TRPCProviderType<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>, {
    keyPrefix: false;
}>
TRPCProvider
} from '../utils/trpc';
function function makeQueryClient(): QueryClientmakeQueryClient() { return new new QueryClient(config?: QueryClientConfig): QueryClientQueryClient({ QueryClientConfig.defaultOptions?: DefaultOptions<Error> | undefineddefaultOptions: { DefaultOptions<Error>.queries?: OmitKeyof<QueryObserverOptions<unknown, Error, unknown, unknown, readonly unknown[], never>, "suspense" | "queryKey", "strictly"> | undefinedqueries: { // With SSR, we usually want to set some default staleTime // above 0 to avoid refetching immediately on the client staleTime?: StaleTimeFunction<unknown, Error, unknown, readonly unknown[]> | undefinedstaleTime: 60 * 1000, }, }, }); } let let browserQueryClient: QueryClient | undefinedbrowserQueryClient: class QueryClientQueryClient | undefined = var undefinedundefined; function function getQueryClient(): QueryClientgetQueryClient() { if (typeof var window: Window & typeof globalThiswindow === 'undefined') { // Server: always make a new query client return function makeQueryClient(): QueryClientmakeQueryClient(); } else { // Browser: make a new query client if we don't already have one // This is very important, so we don't re-make a new client if React // suspends during the initial render. This may not be needed if we // have a suspense boundary BELOW the creation of the query client if (!let browserQueryClient: QueryClient | undefinedbrowserQueryClient) let browserQueryClient: QueryClient | undefinedbrowserQueryClient = function makeQueryClient(): QueryClientmakeQueryClient(); return let browserQueryClient: QueryClientbrowserQueryClient; } } export function function App(): JSX.ElementApp() { const const queryClient: QueryClientqueryClient = function getQueryClient(): QueryClientgetQueryClient(); const [
const trpcClient: TRPCClient<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>>
trpcClient
] =
useState<TRPCClient<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>>>(initialState: TRPCClient<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<...>>> | (() => TRPCClient<...>)): [...] (+1 overload)
useState
(() =>
createTRPCClient<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>>(opts: CreateTRPCClientOptions<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<...>>>): TRPCClient<...>
createTRPCClient
<
type AppRouter = Router<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>> & DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>
AppRouter
>({
links: TRPCLink<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>>[]
links
: [
httpBatchLink<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>>(opts: HTTPBatchLinkOptions<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}>): TRPCLink<...>
httpBatchLink
({
url: string | URLurl: 'http://localhost:2022', }), ], }), ); return ( <const QueryClientProvider: ({ client, children }: QueryClientProviderProps) => React.JSX.ElementQueryClientProvider client: QueryClientclient={const queryClient: QueryClientqueryClient}> <
const TRPCProvider: TRPCProviderType<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>, {
    keyPrefix: false;
}>
TRPCProvider
trpcClient: TRPCClient<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>>
trpcClient
={
const trpcClient: TRPCClient<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>>
trpcClient
} queryClient: QueryClientqueryClient={const queryClient: QueryClientqueryClient}>
{null /* Your app here */} </
const TRPCProvider: TRPCProviderType<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>, {
    keyPrefix: false;
}>
TRPCProvider
>
</const QueryClientProvider: ({ client, children }: QueryClientProviderProps) => React.JSX.ElementQueryClientProvider> ); }

3b. Set up with Query/Mutation Key Prefixing enabled

If you want to prefix all queries and mutations with a specific key, see Query Key Prefixing for setup and usage examples.

3c. Set up without React context

When building an SPA using only client-side rendering with something like Vite, you can create the QueryClient and tRPC client outside of React context as singletons.

utils/trpc.ts
import { class QueryClientQueryClient } from '@tanstack/react-query';
import { function createTRPCClient<TRouter extends AnyRouter>(opts: CreateTRPCClientOptions<TRouter>): TRPCClient<TRouter>createTRPCClient, function httpBatchLink<TRouter extends AnyRouter>(opts: HTTPBatchLinkOptions<TRouter["_def"]["_config"]["$types"]>): TRPCLink<TRouter>httpBatchLink } from '@trpc/client';
import { 
function createTRPCOptionsProxy<TRouter extends AnyRouter, TFeatureFlags extends FeatureFlags = {
    keyPrefix: false;
}>(opts: TRPCOptionsProxyOptions<TRouter, TFeatureFlags>): TRPCOptionsProxy<TRouter, TFeatureFlags>
createTRPCOptionsProxy
} from '@trpc/tanstack-react-query';
import type {
type AppRouter = Router<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>> & DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>
AppRouter
} from '../server/router';
export const const queryClient: QueryClientqueryClient = new new QueryClient(config?: QueryClientConfig): QueryClientQueryClient(); const
const trpcClient: TRPCClient<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>>
trpcClient
=
createTRPCClient<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>>(opts: CreateTRPCClientOptions<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<...>>>): TRPCClient<...>
createTRPCClient
<
type AppRouter = Router<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>> & DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>
AppRouter
>({
links: TRPCLink<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>>[]
links
: [
httpBatchLink<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>>(opts: HTTPBatchLinkOptions<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}>): TRPCLink<...>
httpBatchLink
({ url: string | URLurl: 'http://localhost:2022' })],
}); export const
const trpc: TRPCOptionsProxy<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>, {
    keyPrefix: false;
}>
trpc
=
createTRPCOptionsProxy<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>, {
    keyPrefix: false;
}>(opts: TRPCOptionsProxyOptions<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<...>>, {
    keyPrefix: false;
}>): TRPCOptionsProxy<...>
createTRPCOptionsProxy
<
type AppRouter = Router<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>> & DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>
AppRouter
>({
TRPCOptionsProxyOptionsExternal<BuiltRouter<{ ctx: object; meta: object; errorShape: DefaultErrorShape; transformer: false; }, DecorateCreateRouterOptions<{ getUser: QueryProcedure<{ input: { id: string; }; output: { name: string; }; meta: object; errorShape: DefaultErrorShape; }>; createUser: MutationProcedure<...>; }>>>.client: TRPCClient<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>> | TRPCUntypedClient<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<...>>>
client
:
const trpcClient: TRPCClient<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>>
trpcClient
,
queryClient: QueryClient | (() => QueryClient)queryClient, });
components/App.tsx
import { const QueryClientProvider: ({ client, children }: QueryClientProviderProps) => React.JSX.ElementQueryClientProvider } from '@tanstack/react-query';
import { const queryClient: QueryClientqueryClient } from '../utils/trpc';

export function function App(): JSX.ElementApp() {
  return (
    <const QueryClientProvider: ({ client, children }: QueryClientProviderProps) => React.JSX.ElementQueryClientProvider client: QueryClientclient={const queryClient: QueryClientqueryClient}>
      {/* Your app here */}
    </const QueryClientProvider: ({ client, children }: QueryClientProviderProps) => React.JSX.ElementQueryClientProvider>
  );
}

4. Fetch data

You can now use the tRPC React Query integration to call queries and mutations on your API.

components/user-list.tsx
import { function useMutation<TData = unknown, TError = Error, TVariables = void, TOnMutateResult = unknown>(options: UseMutationOptions<TData, TError, TVariables, TOnMutateResult>, queryClient?: QueryClient): UseMutationResult<TData, TError, TVariables, TOnMutateResult>useMutation, function useQuery<TQueryFnData = unknown, TError = Error, TData = TQueryFnData, TQueryKey extends QueryKey = readonly unknown[]>(options: DefinedInitialDataOptions<TQueryFnData, TError, TData, TQueryKey>, queryClient?: QueryClient): DefinedUseQueryResult<TData, TError> (+2 overloads)useQuery } from '@tanstack/react-query';
import { 
const useTRPC: () => TRPCOptionsProxy<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>, {
    keyPrefix: false;
}>
useTRPC
} from '../utils/trpc';
export default function function UserList(): JSX.ElementUserList() { const
const trpc: TRPCOptionsProxy<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>, {
    keyPrefix: false;
}>
trpc
=
function useTRPC(): TRPCOptionsProxy<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>, {
    keyPrefix: false;
}>
useTRPC
(); // use `import { trpc } from './utils/trpc'` if you're using the singleton pattern
const
const userQuery: UseQueryResult<() => never, TRPCClientErrorLike<{
    transformer: false;
    errorShape: DefaultErrorShape;
}>>
userQuery
=
useQuery<() => never, TRPCClientErrorLike<{
    transformer: false;
    errorShape: DefaultErrorShape;
}>, () => never, TRPCQueryKeyWithoutPrefix>(options: UndefinedInitialDataOptions<() => never, TRPCClientErrorLike<{
    transformer: false;
    errorShape: DefaultErrorShape;
}>, () => never, TRPCQueryKeyWithoutPrefix>, queryClient?: QueryClient): UseQueryResult<() => never, TRPCClientErrorLike<{
    transformer: false;
    errorShape: DefaultErrorShape;
}>> (+2 overloads)
useQuery
(
const trpc: TRPCOptionsProxy<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>, {
    keyPrefix: false;
}>
trpc
.
getUser: DecorateQueryProcedure<{
    input: {
        id: string;
    };
    output: {
        name: string;
    };
    transformer: false;
    errorShape: DefaultErrorShape;
    featureFlags: {
        keyPrefix: false;
    };
}> & Record<string, never>
getUser
.
DecorateQueryProcedure<{ input: { id: string; }; output: { name: string; }; transformer: false; errorShape: DefaultErrorShape; featureFlags: { keyPrefix: false; }; }>.queryOptions: TRPCQueryOptions
<() => never, () => never>(input: {
    id: string;
}, opts?: UnusedSkipTokenTRPCQueryOptionsIn<() => never, () => never, TRPCClientErrorLike<{
    transformer: false;
    errorShape: DefaultErrorShape;
}>, {
    keyPrefix: false;
}> | undefined) => UnusedSkipTokenTRPCQueryOptionsOut<() => never, () => never, TRPCClientErrorLike<{
    transformer: false;
    errorShape: DefaultErrorShape;
}>, {
    keyPrefix: false;
}> (+2 overloads)
queryOptions
({ id: stringid: 'id_bilbo' }));
const
const userCreator: UseMutationResult<string, TRPCClientErrorLike<{
    input: {
        name: string;
    };
    output: string;
    transformer: false;
    errorShape: DefaultErrorShape;
    featureFlags: {
        keyPrefix: false;
    };
}>, {
    name: string;
}, undefined>
userCreator
=
useMutation<string, TRPCClientErrorLike<{
    input: {
        name: string;
    };
    output: string;
    transformer: false;
    errorShape: DefaultErrorShape;
    featureFlags: {
        keyPrefix: false;
    };
}>, {
    name: string;
}, undefined>(options: UseMutationOptions<string, TRPCClientErrorLike<{
    input: {
        name: string;
    };
    output: string;
    transformer: false;
    errorShape: DefaultErrorShape;
    featureFlags: {
        keyPrefix: false;
    };
}>, {
    name: string;
}, undefined>, queryClient?: QueryClient): UseMutationResult<...>
useMutation
(
const trpc: TRPCOptionsProxy<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    getUser: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    createUser: MutationProcedure<{
        input: {
            name: string;
        };
        output: string;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>, {
    keyPrefix: false;
}>
trpc
.
createUser: DecorateMutationProcedure<{
    input: {
        name: string;
    };
    output: string;
    transformer: false;
    errorShape: DefaultErrorShape;
    featureFlags: {
        keyPrefix: false;
    };
}>
createUser
.
DecorateMutationProcedure<{ input: { name: string; }; output: string; transformer: false; errorShape: DefaultErrorShape; featureFlags: { keyPrefix: false; }; }>.mutationOptions: TRPCMutationOptions
<undefined>(opts?: TRPCMutationOptionsIn<{
    name: string;
}, TRPCClientErrorLike<{
    input: {
        name: string;
    };
    output: string;
    transformer: false;
    errorShape: DefaultErrorShape;
    featureFlags: {
        keyPrefix: false;
    };
}>, string, undefined, {
    keyPrefix: false;
}> | undefined) => TRPCMutationOptionsOut<{
    name: string;
}, TRPCClientErrorLike<{
    input: {
        name: string;
    };
    output: string;
    transformer: false;
    errorShape: DefaultErrorShape;
    featureFlags: {
        keyPrefix: false;
    };
}>, string, undefined, {
    keyPrefix: false;
}>
mutationOptions
());
return ( <React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div> <React.JSX.IntrinsicElements.p: React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>p>{
const userQuery: UseQueryResult<() => never, TRPCClientErrorLike<{
    transformer: false;
    errorShape: DefaultErrorShape;
}>>
userQuery
.data: (() => never) | undefineddata?.Function.name: string | undefinedname}</React.JSX.IntrinsicElements.p: React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>p>
<React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>button React.DOMAttributes<HTMLButtonElement>.onClick?: React.MouseEventHandler<HTMLButtonElement> | undefinedonClick={() =>
const userCreator: UseMutationResult<string, TRPCClientErrorLike<{
    input: {
        name: string;
    };
    output: string;
    transformer: false;
    errorShape: DefaultErrorShape;
    featureFlags: {
        keyPrefix: false;
    };
}>, {
    name: string;
}, undefined>
userCreator
.
mutate: (variables: {
    name: string;
}, options?: MutateOptions<string, TRPCClientErrorLike<{
    input: {
        name: string;
    };
    output: string;
    transformer: false;
    errorShape: DefaultErrorShape;
    featureFlags: {
        keyPrefix: false;
    };
}>, {
    name: string;
}, undefined> | undefined) => void
mutate
({ name: stringname: 'Frodo' })}>
Create Frodo </React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>button> </React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div> ); }

5. Invalidate queries after a mutation

There is no tRPC-specific cache API: use TanStack's QueryClient with the keys and filters from trpc. queryFilter() matches one procedure, for every input if you leave the input out, pathFilter() matches every query under a router, and trpc.pathFilter() matches every tRPC query. See Usage for all of them.

components/create-user.tsx
import { function useMutation<TData = unknown, TError = Error, TVariables = void, TOnMutateResult = unknown>(options: UseMutationOptions<TData, TError, TVariables, TOnMutateResult>, queryClient?: QueryClient): UseMutationResult<TData, TError, TVariables, TOnMutateResult>useMutation, const useQueryClient: (queryClient?: QueryClient) => QueryClientuseQueryClient } from '@tanstack/react-query';
import { 
const useTRPC: () => TRPCOptionsProxy<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    user: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        byId: QueryProcedure<{
            input: {
                id: string;
            };
            output: {
                id: string;
                name: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        create: MutationProcedure<{
            input: {
                name: string;
            };
            output: {
                id: string;
                name: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
    }>>;
}>>, {
    ...;
}>
useTRPC
} from '../utils/trpc';
export function function CreateUser(): JSX.ElementCreateUser() { const
const trpc: TRPCOptionsProxy<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    user: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        byId: QueryProcedure<{
            input: {
                id: string;
            };
            output: {
                id: string;
                name: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        create: MutationProcedure<{
            input: {
                name: string;
            };
            output: {
                id: string;
                name: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
    }>>;
}>>, {
    ...;
}>
trpc
=
function useTRPC(): TRPCOptionsProxy<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    user: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        byId: QueryProcedure<{
            input: {
                id: string;
            };
            output: {
                id: string;
                name: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        create: MutationProcedure<{
            input: {
                name: string;
            };
            output: {
                id: string;
                name: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
    }>>;
}>>, {
    ...;
}>
useTRPC
();
const const queryClient: QueryClientqueryClient = function useQueryClient(queryClient?: QueryClient): QueryClientuseQueryClient(); const
const userCreator: UseMutationResult<{
    id: string;
    name: string;
}, TRPCClientErrorLike<{
    input: {
        name: string;
    };
    output: {
        id: string;
        name: string;
    };
    transformer: false;
    errorShape: DefaultErrorShape;
    featureFlags: {
        keyPrefix: false;
    };
}>, {
    name: string;
}, undefined>
userCreator
=
useMutation<{
    id: string;
    name: string;
}, TRPCClientErrorLike<{
    input: {
        name: string;
    };
    output: {
        id: string;
        name: string;
    };
    transformer: false;
    errorShape: DefaultErrorShape;
    featureFlags: {
        keyPrefix: false;
    };
}>, {
    name: string;
}, undefined>(options: UseMutationOptions<{
    id: string;
    name: string;
}, TRPCClientErrorLike<{
    input: {
        name: string;
    };
    output: {
        id: string;
        name: string;
    };
    transformer: false;
    errorShape: DefaultErrorShape;
    featureFlags: {
        keyPrefix: false;
    };
}>, {
    name: string;
}, undefined>, queryClient?: QueryClient): UseMutationResult<...>
useMutation
(
const trpc: TRPCOptionsProxy<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    user: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        byId: QueryProcedure<{
            input: {
                id: string;
            };
            output: {
                id: string;
                name: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        create: MutationProcedure<{
            input: {
                name: string;
            };
            output: {
                id: string;
                name: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
    }>>;
}>>, {
    ...;
}>
trpc
.
user: DecoratedRouterRecord<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    byId: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            id: string;
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    create: MutationProcedure<{
        input: {
            name: string;
        };
        output: {
            id: string;
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>, {
    ...;
}> & DecorateRouterKeyable<...>
user
.
create: DecorateMutationProcedure<{
    input: {
        name: string;
    };
    output: {
        id: string;
        name: string;
    };
    transformer: false;
    errorShape: DefaultErrorShape;
    featureFlags: {
        keyPrefix: false;
    };
}>
create
.
DecorateMutationProcedure<{ input: { name: string; }; output: { id: string; name: string; }; transformer: false; errorShape: DefaultErrorShape; featureFlags: { keyPrefix: false; }; }>.mutationOptions: TRPCMutationOptions
<undefined>(opts?: TRPCMutationOptionsIn<{
    name: string;
}, TRPCClientErrorLike<{
    input: {
        name: string;
    };
    output: {
        id: string;
        name: string;
    };
    transformer: false;
    errorShape: DefaultErrorShape;
    featureFlags: {
        keyPrefix: false;
    };
}>, {
    id: string;
    name: string;
}, undefined, {
    keyPrefix: false;
}> | undefined) => TRPCMutationOptionsOut<{
    name: string;
}, TRPCClientErrorLike<{
    input: {
        name: string;
    };
    output: {
        id: string;
        name: string;
    };
    transformer: false;
    errorShape: DefaultErrorShape;
    featureFlags: {
        keyPrefix: false;
    };
}>, {
    id: string;
    name: string;
}, undefined, {
    keyPrefix: false;
}>
mutationOptions
({
onSuccess?: ((data: {
    id: string;
    name: string;
}, variables: {
    name: string;
}, onMutateResult: undefined, context: MutationFunctionContext) => Promise<unknown> | unknown) | undefined
onSuccess
: async (
user: {
    id: string;
    name: string;
}
user
) => {
// Write the new user into the cache... const queryClient: QueryClientqueryClient.
QueryClient.setQueryData<unknown, TRPCQueryKeyWithoutPrefix & {
    [dataTagSymbol]: {
        id: string;
        name: string;
    };
    [dataTagErrorSymbol]: TRPCClientErrorLike<{
        transformer: false;
        errorShape: DefaultErrorShape;
    }>;
}, {
    id: string;
    name: string;
}>(queryKey: TRPCQueryKeyWithoutPrefix & {
    [dataTagSymbol]: {
        id: string;
        name: string;
    };
    [dataTagErrorSymbol]: TRPCClientErrorLike<{
        transformer: false;
        errorShape: DefaultErrorShape;
    }>;
}, updater: Updater<...>, options?: SetDataOptions): NoInfer<{
    id: string;
    name: string;
}> | undefined
setQueryData
(
const trpc: TRPCOptionsProxy<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    user: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        byId: QueryProcedure<{
            input: {
                id: string;
            };
            output: {
                id: string;
                name: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        create: MutationProcedure<{
            input: {
                name: string;
            };
            output: {
                id: string;
                name: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
    }>>;
}>>, {
    ...;
}>
trpc
.
user: DecoratedRouterRecord<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    byId: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            id: string;
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    create: MutationProcedure<{
        input: {
            name: string;
        };
        output: {
            id: string;
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>, {
    ...;
}> & DecorateRouterKeyable<...>
user
.
byId: DecorateQueryProcedure<{
    input: {
        id: string;
    };
    output: {
        id: string;
        name: string;
    };
    transformer: false;
    errorShape: DefaultErrorShape;
    featureFlags: {
        keyPrefix: false;
    };
}> & Record<string, never>
byId
.
DecorateQueryProcedure<{ input: { id: string; }; output: { id: string; name: string; }; transformer: false; errorShape: DefaultErrorShape; featureFlags: { keyPrefix: false; }; }>.queryKey: (input?: Partial<{
    id: string;
}> | undefined) => TRPCQueryKeyWithoutPrefix & {
    [dataTagSymbol]: {
        id: string;
        name: string;
    };
    [dataTagErrorSymbol]: TRPCClientErrorLike<{
        transformer: false;
        errorShape: DefaultErrorShape;
    }>;
}
queryKey
({ id?: string | undefinedid:
user: {
    id: string;
    name: string;
}
user
.id: stringid }),
user: {
    id: string;
    name: string;
}
user
);
// ...and refetch every query under the `user` router await const queryClient: QueryClientqueryClient.QueryClient.invalidateQueries<TRPCQueryKeyWithoutPrefix>(filters?: InvalidateQueryFilters<TRPCQueryKeyWithoutPrefix> | undefined, options?: InvalidateOptions): Promise<void>invalidateQueries(
const trpc: TRPCOptionsProxy<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    user: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        byId: QueryProcedure<{
            input: {
                id: string;
            };
            output: {
                id: string;
                name: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        create: MutationProcedure<{
            input: {
                name: string;
            };
            output: {
                id: string;
                name: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
    }>>;
}>>, {
    ...;
}>
trpc
.
user: DecoratedRouterRecord<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    byId: QueryProcedure<{
        input: {
            id: string;
        };
        output: {
            id: string;
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    create: MutationProcedure<{
        input: {
            name: string;
        };
        output: {
            id: string;
            name: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>, {
    ...;
}> & DecorateRouterKeyable<...>
user
.DecorateRouterKeyable<{ keyPrefix: false; }>.pathFilter: (filters?: QueryFilters<TRPCQueryKeyWithoutPrefix> | undefined) => WithRequired<QueryFilters<TRPCQueryKeyWithoutPrefix>, "queryKey">pathFilter());
}, }), ); return ( <React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>button React.DOMAttributes<HTMLButtonElement>.onClick?: React.MouseEventHandler<HTMLButtonElement> | undefinedonClick={() =>
const userCreator: UseMutationResult<{
    id: string;
    name: string;
}, TRPCClientErrorLike<{
    input: {
        name: string;
    };
    output: {
        id: string;
        name: string;
    };
    transformer: false;
    errorShape: DefaultErrorShape;
    featureFlags: {
        keyPrefix: false;
    };
}>, {
    name: string;
}, undefined>
userCreator
.
mutate: (variables: {
    name: string;
}, options?: MutateOptions<{
    id: string;
    name: string;
}, TRPCClientErrorLike<{
    input: {
        name: string;
    };
    output: {
        id: string;
        name: string;
    };
    transformer: false;
    errorShape: DefaultErrorShape;
    featureFlags: {
        keyPrefix: false;
    };
}>, {
    name: string;
}, undefined> | undefined) => void
mutate
({ name: stringname: 'Frodo' })}>
Create Frodo </React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>button> ); }

Common mistakes

  • Calling queryFilter() on a router. queryOptions, queryKey and queryFilter only exist on query procedures. For a router, use pathKey() and pathFilter().
  • Writing query keys by hand. A useQuery({ queryKey: ['user', id], queryFn }) that calls the tRPC client works, but its key isn't tRPC's, so queryFilter()/pathFilter() invalidations and server-prefetched data never match it. Use the trpc factories instead.
  • Using the classic hooks. trpc.user.byId.useQuery() and trpc.useUtils() belong to the classic @trpc/react-query client. In this package, pass trpc.*.queryOptions() to TanStack's hooks and use useQueryClient() for the cache. See Migrating.
  • Calling useTRPC() outside the provider. It throws useTRPC() can only be used inside of a <TRPCProvider>. Mount TRPCProvider, with the same queryClient you give QueryClientProvider, above every component that calls useTRPC(). The singleton setup has no provider: import trpc instead.
  • Sharing one QueryClient across server requests. A module-level new QueryClient() is fine in a client-only SPA, but with server rendering it leaks one user's cache into another's. Create one per request on the server, as getQueryClient() does above.