Skip to content
tRPC

Set up with React Server Components

On this page

This guide is an overview of how one may use tRPC with a React Server Components (RSC) framework such as Next.js App Router. Be aware that RSC on its own solves a lot of the same problems tRPC was designed to solve, so you may not need tRPC at all.

There is also not a one-size-fits-all way to integrate tRPC with RSCs, so see this guide as a starting point and adjust it to your needs and preferences.

Add tRPC to existing projects

1. Install deps

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

2. Create a tRPC router

Initialize your tRPC backend in trpc/init.ts using the initTRPC function, and create your first router. We're going to make a simple "hello world" router and procedure here - but for deeper information on creating your tRPC API you should refer to the Quickstart guide and Backend usage docs for tRPC information.

View sample backend
trpc/init.ts
import { const initTRPC: TRPCBuilder<object, object>initTRPC } from '@trpc/server';
import { function cache<CachedFunction extends Function>(fn: CachedFunction): CachedFunctioncache } from 'react';

export const 
const createTRPCContext: () => Promise<{
    userId: string;
}>
createTRPCContext
=
cache<() => Promise<{
    userId: string;
}>>(fn: () => Promise<{
    userId: string;
}>): () => Promise<{
    userId: string;
}>
cache
(async () => {
/** * @see: https://trpc.io/docs/server/context */ return { userId: stringuserId: 'user_123' }; }); // Avoid exporting the entire t-object // since it's not very descriptive. // For instance, the use of a t variable // is common in i18n libraries. const
const t: TRPCRootObject<object, object, {}, {
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}>
t
= const initTRPC: TRPCBuilder<object, object>initTRPC.
TRPCBuilder<object, object>.create<{}>(opts?: {} | undefined): TRPCRootObject<object, object, {}, {
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}>
create
({
/** * @see https://trpc.io/docs/server/data-transformers */ // transformer: superjson, }); // Base router and procedure helpers export const
const createTRPCRouter: RouterBuilder<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}>
createTRPCRouter
=
const t: TRPCRootObject<object, object, {}, {
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}>
t
.
TRPCRootObject<object, object, {}, { ctx: object; meta: object; errorShape: DefaultErrorShape; transformer: false; }>.router: RouterBuilder<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}>
router
;
export const
const createCallerFactory: RouterCallerFactory<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}>
createCallerFactory
=
const t: TRPCRootObject<object, object, {}, {
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}>
t
.
TRPCRootObject<object, object, {}, { ctx: object; meta: object; errorShape: DefaultErrorShape; transformer: false; }>.createCallerFactory: RouterCallerFactory<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}>
createCallerFactory
;
export const const baseProcedure: ProcedureBuilder<object, object, object, UnsetMarker, UnsetMarker, UnsetMarker, UnsetMarker, false, DefaultErrorShape>baseProcedure =
const t: TRPCRootObject<object, object, {}, {
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}>
t
.TRPCRootObject<object, object, {}, { ctx: object; meta: object; errorShape: DefaultErrorShape; transformer: false; }>.procedure: ProcedureBuilder<object, object, object, UnsetMarker, UnsetMarker, UnsetMarker, UnsetMarker, false, DefaultErrorShape>procedure;

trpc/routers/_app.ts
import { import zz } from 'zod';
import { const baseProcedure: ProcedureBuilder<object, object, object, UnsetMarker, UnsetMarker, UnsetMarker, UnsetMarker, false, DefaultErrorShape>baseProcedure, 
const createTRPCRouter: RouterBuilder<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}>
createTRPCRouter
} from '../init';
export const
const appRouter: BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>
appRouter
=
createTRPCRouter<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>(_: {
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}): BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>
createTRPCRouter
({
hello: QueryProcedure<{
    input: {
        text: string;
    };
    output: {
        greeting: string;
    };
    meta: object;
    errorShape: DefaultErrorShape;
}>
hello
: const baseProcedure: ProcedureBuilder<object, object, object, UnsetMarker, UnsetMarker, UnsetMarker, UnsetMarker, false, DefaultErrorShape>baseProcedure
.
ProcedureBuilder<object, object, object, UnsetMarker, UnsetMarker, UnsetMarker, UnsetMarker, false, DefaultErrorShape>.input<z.ZodObject<{
    text: z.ZodString;
}, z.core.$strip>>(schema: z.ZodObject<{
    text: z.ZodString;
}, z.core.$strip>): ProcedureBuilder<object, object, object, {
    text: string;
}, {
    text: string;
}, UnsetMarker, UnsetMarker, false, DefaultErrorShape>
input
(
import zz.
function object<{
    text: z.ZodString;
}>(shape?: {
    text: z.ZodString;
} | undefined, params?: string | {
    error?: string | z.core.$ZodErrorMap<NonNullable<z.core.$ZodIssueUnrecognizedKeys | z.core.$ZodIssueInvalidType<unknown>>> | undefined;
    message?: string | undefined | undefined;
} | undefined): z.ZodObject<{
    text: z.ZodString;
}, z.core.$strip>
object
({
text: z.ZodStringtext: import zz.function string(params?: string | z.core.$ZodStringParams): z.ZodString (+1 overload)string(), }), ) .
ProcedureBuilder<object, object, object, { text: string; }, { text: string; }, UnsetMarker, UnsetMarker, false, DefaultErrorShape>.query<{
    greeting: string;
}>(resolver: ProcedureResolver<object, object, object, {
    text: string;
}, UnsetMarker, {
    greeting: string;
}>): QueryProcedure<{
    input: {
        text: string;
    };
    output: {
        greeting: string;
    };
    meta: object;
    errorShape: DefaultErrorShape;
}>
query
((
opts: ProcedureResolverOptions<object, object, object, {
    text: string;
}>
opts
) => {
return { greeting: stringgreeting: `hello ${
opts: ProcedureResolverOptions<object, object, object, {
    text: string;
}>
opts
.
ProcedureResolverOptions<object, object, object, { text: string; }>.input: {
    text: string;
}
input
.text: stringtext}`,
}; }), }); // export type definition of API export type
type AppRouter = Router<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>> & DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>
AppRouter
= typeof
const appRouter: BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>
appRouter
;

app/api/trpc/[trpc]/route.ts
import { function fetchRequestHandler<TRouter extends AnyRouter>(opts: FetchHandlerRequestOptions<TRouter>): Promise<Response>fetchRequestHandler } from '@trpc/server/adapters/fetch';
import { 
const createTRPCContext: () => Promise<{
    userId: string;
}>
createTRPCContext
} from '../../../../trpc/init';
import {
const appRouter: BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>
appRouter
} from '../../../../trpc/routers/_app';
const const handler: (req: Request) => Promise<Response>handler = (req: Requestreq: Request) =>
fetchRequestHandler<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>>(opts: FetchHandlerRequestOptions<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>>): Promise<Response>
fetchRequestHandler
({
endpoint: stringendpoint: '/api/trpc', req: Requestreq,
BaseHandlerOptions<BuiltRouter<{ ctx: object; meta: object; errorShape: DefaultErrorShape; transformer: false; }, DecorateCreateRouterOptions<{ hello: QueryProcedure<{ input: { text: string; }; output: { greeting: string; }; meta: object; errorShape: DefaultErrorShape; }>; }>>, Request>.router: BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>
router
:
const appRouter: BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>
appRouter
,
createContext?: FetchCreateContextFn<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>> | undefined
createContext
:
const createTRPCContext: () => Promise<{
    userId: string;
}>
createTRPCContext
,
}); export { const handler: (req: Request) => Promise<Response>handler as
const GET: (req: Request) => Promise<Response>
export GET
GET
, const handler: (req: Request) => Promise<Response>handler as
const POST: (req: Request) => Promise<Response>
export POST
POST
};

3. Create a Query Client factory

Create a shared file trpc/query-client.ts that exports a function that creates a QueryClient instance.

trpc/query-client.ts
import {
  function defaultShouldDehydrateQuery(query: Query): booleandefaultShouldDehydrateQuery,
  class QueryClientQueryClient,
} from '@tanstack/react-query';
import class superjsonsuperjson from 'superjson';

export 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: {
        staleTime?: StaleTimeFunction<unknown, Error, unknown, readonly unknown[]> | undefinedstaleTime: 30 * 1000,
      },
      DefaultOptions<Error>.dehydrate?: DehydrateOptions | undefineddehydrate: {
        // serializeData: superjson.serialize,
        DehydrateOptions.shouldDehydrateQuery?: ((query: Query) => boolean) | undefinedshouldDehydrateQuery: (query: Query<unknown, Error, unknown, readonly unknown[]>query) =>
          function defaultShouldDehydrateQuery(query: Query): booleandefaultShouldDehydrateQuery(query: Query<unknown, Error, unknown, readonly unknown[]>query) ||
          query: Query<unknown, Error, unknown, readonly unknown[]>query.Query<unknown, Error, unknown, readonly unknown[]>.state: QueryState<unknown, Error>state.QueryState<unknown, Error>.status: QueryStatusstatus === 'pending',
      },
      
DefaultOptions<Error>.hydrate?: {
    deserializeData?: TransformerFn;
    queries?: QueryOptions;
    mutations?: MutationOptions<unknown, DefaultError, unknown, unknown>;
} | undefined
hydrate
: {
// deserializeData: superjson.deserialize, }, }, }); }

We're setting a few default options here:

  • staleTime: With SSR, we usually want to set some default staleTime above 0 to avoid refetching immediately on the client.
  • shouldDehydrateQuery: This is a function that determines whether a query should be dehydrated or not. Since the RSC transport protocol supports hydrating promises over the network, we extend the defaultShouldDehydrateQuery function to also include queries that are still pending. This will allow us to start prefetching in a server component high up the tree, then consuming that promise in a client component further down.
  • serializeData and deserializeData (optional): If you set up a data transformer in the previous step, set this option to make sure the data is serialized correctly when hydrating the query client over the server-client boundary.

4. Create a tRPC client for Client Components

The trpc/client.tsx is the entrypoint when consuming your tRPC API from client components. In here, import the type definition of your tRPC router and create typesafe hooks using createTRPCReact. We'll also export our context provider from this file.

trpc/client.tsx
'use client';

// ^-- to make sure we can mount the Provider from a server component
import type { class QueryClientQueryClient } from '@tanstack/react-query';
import { const QueryClientProvider: ({ client, children }: QueryClientProviderProps) => React.JSX.ElementQueryClientProvider } from '@tanstack/react-query';
import { function httpBatchLink<TRouter extends AnyRouter>(opts: HTTPBatchLinkOptions<TRouter["_def"]["_config"]["$types"]>): TRPCLink<TRouter>httpBatchLink } from '@trpc/client';
import { function createTRPCReact<TRouter extends AnyRouter, TSSRContext = unknown>(opts?: CreateTRPCReactOptions<TRouter>): CreateTRPCReact<TRouter, TSSRContext>createTRPCReact } from '@trpc/react-query';
import React, { function useState<S>(initialState: S | (() => S)): [S, React.Dispatch<React.SetStateAction<S>>] (+1 overload)useState } from 'react';
import { function makeQueryClient(): QueryClientmakeQueryClient } from './query-client';
import type { 
type AppRouter = Router<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>> & DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>
AppRouter
} from './routers/_app';
export const
const trpc: CreateTRPCReactBase<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>, unknown> & DecorateRouterRecord<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>
trpc
=
createTRPCReact<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>, unknown>(opts?: CreateTRPCReactOptions<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>> | undefined): CreateTRPCReactBase<...> & DecorateRouterRecord<...>
createTRPCReact
<
type AppRouter = Router<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>> & DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>
AppRouter
>();
let let clientQueryClientSingleton: QueryClientclientQueryClientSingleton: class QueryClientQueryClient; function function getQueryClient(): QueryClientgetQueryClient() { if (typeof var window: Window & typeof globalThiswindow === 'undefined') { // Server: always make a new query client return function makeQueryClient(): QueryClientmakeQueryClient(); } // Browser: use singleton pattern to keep the same query client return (let clientQueryClientSingleton: QueryClientclientQueryClientSingleton ??= function makeQueryClient(): QueryClientmakeQueryClient()); } function function getUrl(): stringgetUrl() { const const base: stringbase = (() => { if (typeof var window: Window & typeof globalThiswindow !== 'undefined') return ''; if (var process: NodeJS.Processprocess.NodeJS.Process.env: NodeJS.ProcessEnvenv.string | undefinedVERCEL_URL) return `https://${var process: NodeJS.Processprocess.NodeJS.Process.env: NodeJS.ProcessEnvenv.stringVERCEL_URL}`; return 'http://localhost:3000'; })(); return `${const base: stringbase}/api/trpc`; } export function
function TRPCProvider(props: Readonly<{
    children: React.ReactNode;
}>): React.JSX.Element
TRPCProvider
(
props: Readonly<{
    children: React.ReactNode;
}>
props
: type Readonly<T> = { readonly [P in keyof T]: T[P]; }Readonly<{
children: React.ReactNodechildren: React.type React.ReactNode = string | number | bigint | boolean | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | React.ReactPortal | Promise<AwaitedReactNode> | null | undefinedReactNode; }>, ) { // NOTE: Avoid useState when initializing the query client if you don't // have a suspense boundary between this and the code that may // suspend because React will throw away the client on the initial // render if it suspends and there is no boundary const const queryClient: QueryClientqueryClient = function getQueryClient(): QueryClientgetQueryClient(); const [
const trpcClient: TRPCClient<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>>
trpcClient
] =
useState<TRPCClient<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>>>(initialState: TRPCClient<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>> | (() => TRPCClient<...>)): [...] (+1 overload)
useState
(() =>
const trpc: CreateTRPCReactBase<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>, unknown> & DecorateRouterRecord<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>
trpc
.
createClient: (opts: CreateTRPCClientOptions<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>>) => TRPCClient<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>>
createClient
({
links: TRPCLink<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>>[]
links
: [
httpBatchLink<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>>(opts: HTTPBatchLinkOptions<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}>): TRPCLink<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<...>>>
httpBatchLink
({
// transformer: superjson, <-- if you use a data transformer url: string | URLurl: function getUrl(): stringgetUrl(), }), ], }), ); return ( <
const trpc: CreateTRPCReactBase<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>, unknown> & DecorateRouterRecord<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>
trpc
.
type Provider: TRPCProvider<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>, unknown>
Provider
TRPCProviderProps<BuiltRouter<{ ctx: object; meta: object; errorShape: DefaultErrorShape; transformer: false; }, DecorateCreateRouterOptions<{ hello: QueryProcedure<{ input: { text: string; }; output: { greeting: string; }; meta: object; errorShape: DefaultErrorShape; }>; }>>, unknown>.client: TRPCClient<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>> | TRPCUntypedClient<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>>
client
={
const trpcClient: TRPCClient<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>>
trpcClient
} queryClient: QueryClientqueryClient={const queryClient: QueryClientqueryClient}>
<const QueryClientProvider: ({ client, children }: QueryClientProviderProps) => React.JSX.ElementQueryClientProvider client: QueryClientclient={const queryClient: QueryClientqueryClient}> {
props: Readonly<{
    children: React.ReactNode;
}>
props
.children: React.ReactNodechildren}
</const QueryClientProvider: ({ client, children }: QueryClientProviderProps) => React.JSX.ElementQueryClientProvider> </
const trpc: CreateTRPCReactBase<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>, unknown> & DecorateRouterRecord<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>
trpc
.
type Provider: TRPCProvider<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>, unknown>
Provider
>
); }

Mount the provider in the root of your application (e.g. app/layout.tsx when using Next.js).

5. Create a tRPC caller for Server Components

To prefetch queries from server components, we use a tRPC caller. The @trpc/react-query/rsc module exports a thin wrapper around createCaller that integrates with your React Query client.

trpc/server.tsx
import 'server-only'; // <-- ensure this file cannot be imported from the client

import { 
function createHydrationHelpers<TRouter extends AnyRouter>(caller: AnyRouter extends TRouter ? TypeError<"Generic parameter missing in `createHydrationHelpers<HERE>`"> : Caller<TRouter>, getQueryClient: () => QueryClient): {
    trpc: DecorateRouterRecord<inferRouterRootTypes<TRouter>, TRouter["_def"]["record"]>;
    HydrateClient: (props: {
        children: React.ReactNode;
    }) => React.JSX.Element;
}
createHydrationHelpers
} from '@trpc/react-query/rsc';
import { function cache<CachedFunction extends Function>(fn: CachedFunction): CachedFunctioncache } from 'react'; import {
const createCallerFactory: RouterCallerFactory<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}>
createCallerFactory
,
const createTRPCContext: () => Promise<{
    userId: string;
}>
createTRPCContext
} from './init';
import { function makeQueryClient(): QueryClientmakeQueryClient } from './query-client'; import {
const appRouter: BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>
appRouter
} from './routers/_app';
// IMPORTANT: Create a stable getter for the query client that // will return the same client during the same request. export const const getQueryClient: () => QueryClientgetQueryClient = cache<() => QueryClient>(fn: () => QueryClient): () => QueryClientcache(function makeQueryClient(): QueryClientmakeQueryClient); const
const caller: DecorateRouterRecord<DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>
caller
=
createCallerFactory<DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>(router: Pick<Router<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>, "_def">): RouterCaller<...>
createCallerFactory
(
const appRouter: BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>
appRouter
)(
const createTRPCContext: () => Promise<{
    userId: string;
}>
createTRPCContext
);
export const {
const trpc: DecorateRouterRecord<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>
trpc
,
const HydrateClient: (props: {
    children: React.ReactNode;
}) => React.JSX.Element
HydrateClient
} =
createHydrationHelpers<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>>(caller: DecorateRouterRecord<DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>, getQueryClient: () => QueryClient): {
    ...;
}
createHydrationHelpers
<typeof
const appRouter: BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>
appRouter
>(
const caller: DecorateRouterRecord<DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        };
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>
caller
,
const getQueryClient: () => QueryClientgetQueryClient, );

Using your API

Now you can use your tRPC API in your app. While you can use the React Query hooks in client components just like you would in any other React app, we can take advantage of the RSC capabilities by prefetching queries in a server component high up the tree. You may be familiar with this concept as "render as you fetch" commonly implemented as loaders. This means the request fires as soon as possible but without suspending until the data is needed by using the useQuery or useSuspenseQuery hooks.

app/page.tsx
import { 
const trpc: DecorateRouterRecord<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        } | undefined;
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>
trpc
,
const HydrateClient: (props: {
    children: React.ReactNode;
}) => React.JSX.Element
HydrateClient
} from '../trpc/server';
import { function ClientGreeting(): anyClientGreeting } from './client-greeting'; export default async function function Home(): Promise<React.JSX.Element>Home() { void
const trpc: DecorateRouterRecord<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        } | undefined;
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>
trpc
.
hello: DecorateProcedure<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, QueryProcedure<{
    input: {
        text: string;
    } | undefined;
    output: {
        greeting: string;
    };
    meta: object;
    errorShape: DefaultErrorShape;
}>>
hello
.
prefetch: (input: void | {
    text: string;
} | undefined, opts?: TRPCFetchQueryOptions<{
    greeting: string;
}, TRPCClientError<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}>> | undefined) => Promise<void>
prefetch
();
return ( <
const HydrateClient: (props: {
    children: React.ReactNode;
}) => React.JSX.Element
HydrateClient
>
<React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div>...</React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div> {/** ... */} <function ClientGreeting(): anyClientGreeting /> </
const HydrateClient: (props: {
    children: React.ReactNode;
}) => React.JSX.Element
HydrateClient
>
); }
app/client-greeting.tsx
'use client';

// <-- hooks can only be used in client components
import { 
const trpc: CreateTRPCReactBase<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        } | undefined;
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>, unknown> & DecorateRouterRecord<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        } | undefined;
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>
trpc
} from '../trpc/client';
export function function ClientGreeting(): React.JSX.ElementClientGreeting() { const
const greeting: UseTRPCQueryResult<{
    greeting: string;
}, TRPCClientErrorLike<{
    input: void | {
        text: string;
    } | undefined;
    output: {
        greeting: string;
    };
    transformer: false;
    errorShape: DefaultErrorShape;
}>>
greeting
=
const trpc: CreateTRPCReactBase<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        } | undefined;
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>, unknown> & DecorateRouterRecord<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        } | undefined;
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>
trpc
.
hello: DecoratedQuery<{
    input: void | {
        text: string;
    } | undefined;
    output: {
        greeting: string;
    };
    transformer: false;
    errorShape: DefaultErrorShape;
}>
hello
.
useQuery: ProcedureUseQuery
<{
    greeting: string;
}, {
    greeting: string;
}>(input: void | {
    text: string;
} | unique symbol | undefined, opts?: UseTRPCQueryOptions<{
    greeting: string;
}, {
    greeting: string;
}, TRPCClientErrorLike<{
    input: void | {
        text: string;
    } | undefined;
    output: {
        greeting: string;
    };
    transformer: false;
    errorShape: DefaultErrorShape;
}>, {
    greeting: string;
}> | undefined) => UseTRPCQueryResult<{
    greeting: string;
}, TRPCClientErrorLike<{
    input: void | {
        text: string;
    } | undefined;
    output: {
        greeting: string;
    };
    transformer: false;
    errorShape: DefaultErrorShape;
}>> (+1 overload)
useQuery
();
if (!
const greeting: UseTRPCQueryResult<{
    greeting: string;
}, TRPCClientErrorLike<{
    input: void | {
        text: string;
    } | undefined;
    output: {
        greeting: string;
    };
    transformer: false;
    errorShape: DefaultErrorShape;
}>>
greeting
.
data: {
    greeting: string;
} | undefined
data
) return <React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div>Loading...</React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div>;
return <React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div>{
const greeting: (TRPCHookResult & QueryObserverRefetchErrorResult<{
    greeting: string;
}, TRPCClientErrorLike<{
    input: void | {
        text: string;
    } | undefined;
    output: {
        greeting: string;
    };
    transformer: false;
    errorShape: DefaultErrorShape;
}>>) | (TRPCHookResult & QueryObserverSuccessResult<{
    greeting: string;
}, TRPCClientErrorLike<{
    input: void | {
        text: string;
    } | undefined;
    output: {
        greeting: string;
    };
    transformer: false;
    errorShape: DefaultErrorShape;
}>>) | (TRPCHookResult & QueryObserverPlaceholderResult<...>)
greeting
.
data: {
    greeting: string;
}
data
.greeting: stringgreeting}</React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div>;
}

Leveraging Suspense

You may prefer handling loading and error states using Suspense and Error Boundaries. You can do this by using the useSuspenseQuery hook.

app/page.tsx
import { 
const trpc: DecorateRouterRecord<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        } | undefined;
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>
trpc
,
const HydrateClient: (props: {
    children: React.ReactNode;
}) => React.JSX.Element
HydrateClient
} from '../trpc/server';
import { const Suspense: React.ExoticComponent<React.SuspenseProps>Suspense } from 'react'; import { class ErrorBoundaryErrorBoundary } from 'react-error-boundary'; import { function ClientGreeting(): anyClientGreeting } from './client-greeting'; export default async function function Home(): Promise<React.JSX.Element>Home() { void
const trpc: DecorateRouterRecord<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        } | undefined;
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>
trpc
.
hello: DecorateProcedure<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, QueryProcedure<{
    input: {
        text: string;
    } | undefined;
    output: {
        greeting: string;
    };
    meta: object;
    errorShape: DefaultErrorShape;
}>>
hello
.
prefetch: (input: void | {
    text: string;
} | undefined, opts?: TRPCFetchQueryOptions<{
    greeting: string;
}, TRPCClientError<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}>> | undefined) => Promise<void>
prefetch
();
return ( <
const HydrateClient: (props: {
    children: React.ReactNode;
}) => React.JSX.Element
HydrateClient
>
<React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div>...</React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div> {/** ... */} <class ErrorBoundaryErrorBoundary fallback: React.ReactNodefallback={<React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div>Something went wrong</React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div>}> <const Suspense: React.ExoticComponent<React.SuspenseProps>Suspense React.SuspenseProps.fallback?: React.ReactNodefallback={<React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div>Loading...</React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div>}> <function ClientGreeting(): anyClientGreeting /> </const Suspense: React.ExoticComponent<React.SuspenseProps>Suspense> </class ErrorBoundaryErrorBoundary> </
const HydrateClient: (props: {
    children: React.ReactNode;
}) => React.JSX.Element
HydrateClient
>
); }
app/client-greeting.tsx
'use client';

import { 
const trpc: CreateTRPCReactBase<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        } | undefined;
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>, unknown> & DecorateRouterRecord<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        } | undefined;
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>
trpc
} from '../trpc/client';
export function function ClientGreeting(): React.JSX.ElementClientGreeting() { const [
const data: {
    greeting: string;
}
data
] =
const trpc: CreateTRPCReactBase<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        } | undefined;
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>, unknown> & DecorateRouterRecord<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        } | undefined;
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>
trpc
.
hello: DecoratedQuery<{
    input: void | {
        text: string;
    } | undefined;
    output: {
        greeting: string;
    };
    transformer: false;
    errorShape: DefaultErrorShape;
}>
hello
.
useSuspenseQuery: <{
    greeting: string;
}, {
    greeting: string;
}>(input: void | {
    text: string;
} | undefined, opts?: UseTRPCSuspenseQueryOptions<{
    greeting: string;
}, {
    greeting: string;
}, TRPCClientErrorLike<{
    input: void | {
        text: string;
    } | undefined;
    output: {
        greeting: string;
    };
    transformer: false;
    errorShape: DefaultErrorShape;
}>> | undefined) => [{
    greeting: string;
}, UseSuspenseQueryResult<{
    greeting: string;
}, TRPCClientErrorLike<{
    input: void | {
        text: string;
    } | undefined;
    output: {
        greeting: string;
    };
    transformer: false;
    errorShape: DefaultErrorShape;
}>> & TRPCHookResult]
useSuspenseQuery
();
return <React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div>{
const data: {
    greeting: string;
}
data
.greeting: stringgreeting}</React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div>;
}

Getting data in a server component

If you need access to the data in a server component, you can invoke the procedure directly instead of using .prefetch(), just like you use the normal server caller. Please note that this method is detached from your query client and does not store the data in the cache. This means that you cannot use the data in a server component and expect it to be available in the client. This is intentional and explained in more detail in the Advanced Server Rendering guide.

app/page.tsx
import { 
const trpc: DecorateRouterRecord<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        } | undefined;
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>
trpc
} from '../trpc/server';
export default async function function Home(): Promise<React.JSX.Element>Home() { // Use the caller directly without using `.prefetch()` const greeting = await
const trpc: DecorateRouterRecord<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    hello: QueryProcedure<{
        input: {
            text: string;
        } | undefined;
        output: {
            greeting: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>
trpc
.
hello: (input: void | {
    text: string;
} | undefined) => Promise<{
    greeting: string;
}>
hello
();
const greeting: {
    greeting: string;
}
return <React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div>{
const greeting: {
    greeting: string;
}
greeting
.greeting: stringgreeting}</React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div>;
}