Skip to content

tRPC v12 isn’t on npm yet. The @trpc12/* packages on this site can’t be installed until it’s released. Use v11 today

tRPC

ExperimentalReact without TanStack Query might change or go away in any release. Stability

React without TanStack Query

Render-as-you-fetch with use() and Suspense in @trpc12/experimental-react, where cache features are links.

On this page

@trpc12/experimental-react reads tRPC in React with use() and Suspense, without TanStack Query: render-as-you-fetch, after raf-query. A route loader (or an event handler) calls .query(), which starts the request and returns a promise. The component reads that promise with useQuery() and use(). Components don't start requests.

The whole package is experimental: the package name says so, every export is @stability experimental, and the API might change or go away in any release. For a stable React integration, use TanStack Query; React and Next.js compares the three.

Not on npm yet
pnpm add @trpc12/trpc effect @trpc12/experimental-react
npm install @trpc12/trpc effect @trpc12/experimental-react
yarn add @trpc12/trpc effect @trpc12/experimental-react
bun add @trpc12/trpc effect @trpc12/experimental-react

The examples/experimental/react-suspense app uses this package on TanStack Start: a route loader starts the query, and the server render's cache is dehydrated into the browser's client. react-atom is the same page with @trpc12/experimental-react-atom.

import {
  function createReactClient<TSource, const TLinks extends ReadonlyArray<TrpcLink<any, RouterOf<TSource>>>>(opts: ReactClientOptions<TSource, TLinks>): ReactClient<TrpcClient<RouterOf<TSource>, LinksContext<TLinks>, undefined, LinksTypes<TLinks>>>createReactClient,
  function standardLinks(opts?: StandardLinksOptions): StandardLinksstandardLinks,
  function useQuery<T, E>(promise: QueryPromise<T, E>): QueryPromise<T, E>useQuery,
  type type QueryPromise<T, E = unknown> = TrpcPromise<T, E> & Thenable<T>QueryPromise,
} from '@trpc12/experimental-react';
import { function httpLink<TOpts extends HttpLinkOptions>(opts: TOpts): TrpcLink<HttpLinkDecl<TOpts>>httpLink, function routerType<TRouter>(): RouterType<TRouter>routerType } from '@trpc12/trpc/client';
import { const Suspense: React.ExoticComponent<React.SuspenseProps>Suspense, function use<T>(usable: React.Usable<T>): Tuse } from 'react';
import type { 
type AppRouter = {
    post: {
        byId: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: {
                id: string;
            };
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }> | SchemaValidationError<ZodObject<{
                id: ZodString;
            }, $strip>>;
            services: never;
        }>;
        list: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: undefined;
            output: Post[];
            errors: never;
            services: never;
        }>;
        create: Procedure<{
            type: "mutation";
            ctx: Context;
            meta: {};
            input: {
                title: string;
            };
            output: Post;
            errors: TrpcError<...> | SchemaValidationError<...>;
            services: never;
        }>;
    };
}
AppRouter
} from './server';
export const
const trpc: ReactClient<TrpcClient<{
    post: {
        byId: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: {
                id: string;
            };
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }> | SchemaValidationError<ZodObject<{
                id: ZodString;
            }, $strip>>;
            services: never;
        }>;
        list: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: undefined;
            output: Post[];
            errors: never;
            services: never;
        }>;
        create: Procedure<{
            type: "mutation";
            ctx: Context;
            meta: {};
            input: {
                title: string;
            };
            output: Post;
            errors: TrpcError<...> | SchemaValidationError<...>;
            services: never;
        }>;
    };
}, {}, undefined, LinksTypes<...>>>
trpc
=
createReactClient<RouterType<{
    post: {
        byId: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: {
                id: string;
            };
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }> | SchemaValidationError<ZodObject<{
                id: ZodString;
            }, $strip>>;
            services: never;
        }>;
        list: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: undefined;
            output: Post[];
            errors: never;
            services: never;
        }>;
        create: Procedure<{
            type: "mutation";
            ctx: Context;
            meta: {};
            input: {
                title: string;
            };
            output: Post;
            errors: TrpcError<...> | SchemaValidationError<...>;
            services: never;
        }>;
    };
}>, readonly [cache: ...]>(opts: ReactClientOptions<...>): ReactClient<...>
createReactClient
({
TypedClientOptions<RouterType<{ post: { byId: Procedure<{ type: "query"; ctx: Context; meta: {}; input: { id: string; }; output: Post; errors: TrpcError<"NOT_FOUND", { id: string; }> | SchemaValidationError<ZodObject<{ id: ZodString; }, $strip>>; services: never; }>; list: Procedure<...>; create: Procedure<...>; }; }>, readonly [cache: ...]>.router: RouterType<{
    post: {
        byId: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: {
                id: string;
            };
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }> | SchemaValidationError<ZodObject<{
                id: ZodString;
            }, $strip>>;
            services: never;
        }>;
        list: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: undefined;
            output: Post[];
            errors: never;
            services: never;
        }>;
        create: Procedure<{
            type: "mutation";
            ctx: Context;
            meta: {};
            input: {
                title: string;
            };
            output: Post;
            errors: TrpcError<...> | SchemaValidationError<...>;
            services: never;
        }>;
    };
}>
router
:
routerType<{
    post: {
        byId: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: {
                id: string;
            };
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }> | SchemaValidationError<ZodObject<{
                id: ZodString;
            }, $strip>>;
            services: never;
        }>;
        list: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: undefined;
            output: Post[];
            errors: never;
            services: never;
        }>;
        create: Procedure<{
            type: "mutation";
            ctx: Context;
            meta: {};
            input: {
                title: string;
            };
            output: Post;
            errors: TrpcError<...> | SchemaValidationError<...>;
            services: never;
        }>;
    };
}>(): RouterType<...>
routerType
<
type AppRouter = {
    post: {
        byId: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: {
                id: string;
            };
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }> | SchemaValidationError<ZodObject<{
                id: ZodString;
            }, $strip>>;
            services: never;
        }>;
        list: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: undefined;
            output: Post[];
            errors: never;
            services: never;
        }>;
        create: Procedure<{
            type: "mutation";
            ctx: Context;
            meta: {};
            input: {
                title: string;
            };
            output: Post;
            errors: TrpcError<...> | SchemaValidationError<...>;
            services: never;
        }>;
    };
}
AppRouter
>(),
TypedClientOptions<RouterType<{ post: { byId: Procedure<{ type: "query"; ctx: Context; meta: {}; input: { id: string; }; output: Post; errors: TrpcError<"NOT_FOUND", { id: string; }> | SchemaValidationError<ZodObject<{ id: ZodString; }, $strip>>; services: never; }>; list: Procedure<...>; create: Procedure<...>; }; }>, readonly [cache: ...]>.links: readonly [cache: TrpcLink<{}, any>, structuralSharing: TrpcLink<{}, any>, refetchOnMount: TrpcLink<{}, any>, refetchOnWindowFocus: TrpcLink<{}, any>, refetchOnReconnect: TrpcLink<{}, any>, invalidateOnMutation: TrpcLink<{}, any>, retry: TrpcLink<{}, any>, TrpcLink<{
    form: JsonForm;
    provides: "response";
    builtinErrors: "NETWORK_ERROR" | "BAD_RESPONSE" | "STREAM_INTERRUPTED";
}, any>]
links
: [...function standardLinks(opts?: StandardLinksOptions): StandardLinksstandardLinks({ CacheLinkOptions.staleTime?: number | undefinedstaleTime: 10_000 }),
httpLink<{
    url: string;
}>(opts: {
    url: string;
}): TrpcLink<{
    form: JsonForm;
    provides: "response";
    builtinErrors: "NETWORK_ERROR" | "BAD_RESPONSE" | "STREAM_INTERRUPTED";
}, any>
httpLink
({ url: stringurl: '/trpc' })],
}); // The route's loader starts the request; the navigation doesn't wait for it. export const
const loader: (args: {
    params: {
        id: string;
    };
}) => {
    post: QueryPromise<{
        id: string;
        title: string;
        author: string | null;
        createdAt: string;
    }, ClientError<TrpcError<"NOT_FOUND", {
        id: string;
    }> | SchemaValidationError<ZodObject<{
        id: ZodString;
    }, $strip>>, JsonForm, "NETWORK_ERROR" | "BAD_RESPONSE" | "STREAM_INTERRUPTED">>;
}
loader
= (
args: {
    params: {
        id: string;
    };
}
args
: {
params: {
    id: string;
}
params
: { id: stringid: string } }) => ({
post: QueryPromise<{
    id: string;
    title: string;
    author: string | null;
    createdAt: string;
}, ClientError<TrpcError<"NOT_FOUND", {
    id: string;
}> | SchemaValidationError<ZodObject<{
    id: ZodString;
}, $strip>>, JsonForm, "NETWORK_ERROR" | "BAD_RESPONSE" | "STREAM_INTERRUPTED">>
post
:
const trpc: ReactClient<TrpcClient<{
    post: {
        byId: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: {
                id: string;
            };
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }> | SchemaValidationError<ZodObject<{
                id: ZodString;
            }, $strip>>;
            services: never;
        }>;
        list: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: undefined;
            output: Post[];
            errors: never;
            services: never;
        }>;
        create: Procedure<{
            type: "mutation";
            ctx: Context;
            meta: {};
            input: {
                title: string;
            };
            output: Post;
            errors: TrpcError<...> | SchemaValidationError<...>;
            services: never;
        }>;
    };
}, {}, undefined, LinksTypes<...>>>
trpc
.
post: ReactProcedures<ClientRouter<{
    byId: Procedure<{
        type: "query";
        ctx: Context;
        meta: {};
        input: {
            id: string;
        };
        output: Post;
        errors: TrpcError<"NOT_FOUND", {
            id: string;
        }> | SchemaValidationError<ZodObject<{
            id: ZodString;
        }, $strip>>;
        services: never;
    }>;
    list: Procedure<{
        type: "query";
        ctx: Context;
        meta: {};
        input: undefined;
        output: Post[];
        errors: never;
        services: never;
    }>;
    create: Procedure<{
        type: "mutation";
        ctx: Context;
        meta: {};
        input: {
            title: string;
        };
        output: Post;
        errors: TrpcError<...> | SchemaValidationError<...>;
        services: never;
    }>;
}, {}, undefined, LinksTypes<...>>>
post
.
byId: DecorateQuery<[input: {
    id: string;
}, opts?: CallOptions<{}> | undefined], {
    id: string;
    title: string;
    author: string | null;
    createdAt: string;
}, ClientError<...>>
byId
.
DecorateQuery<[input: { id: string; }, opts?: CallOptions<{}> | undefined], { id: string; title: string; author: string | null; createdAt: string; }, ClientError<TrpcError<"NOT_FOUND", { id: string; }> | SchemaValidationError<...>, JsonForm, "NETWORK_ERROR" | ... 1 more ... | "STREAM_INTERRUPTED">>.query(input: {
    id: string;
}, opts?: CallOptions<{}> | undefined): QueryPromise<{
    id: string;
    title: string;
    author: string | null;
    createdAt: string;
}, ClientError<TrpcError<"NOT_FOUND", {
    id: string;
}> | SchemaValidationError<ZodObject<{
    id: ZodString;
}, $strip>>, JsonForm, "NETWORK_ERROR" | "BAD_RESPONSE" | "STREAM_INTERRUPTED">>
query
({ id: stringid:
args: {
    params: {
        id: string;
    };
}
args
.
params: {
    id: string;
}
params
.id: stringid }),
}); function
function Post(props: {
    post: QueryPromise<{
        title: string;
    }>;
}): React.JSX.Element
Post
(
props: {
    post: QueryPromise<{
        title: string;
    }>;
}
props
: {
post: QueryPromise<{
    title: string;
}>
post
: type QueryPromise<T, E = unknown> = TrpcPromise<T, E> & Thenable<T>QueryPromise<{ title: stringtitle: string }> }) {
const
const post: {
    title: string;
}
post
=
use<{
    title: string;
}>(usable: React.Usable<{
    title: string;
}>): {
    title: string;
}
use
(
useQuery<{
    title: string;
}, unknown>(promise: QueryPromise<{
    title: string;
}, unknown>): QueryPromise<{
    title: string;
}, unknown>
useQuery
(
props: {
    post: QueryPromise<{
        title: string;
    }>;
}
props
.
post: QueryPromise<{
    title: string;
}>
post
));
return <React.JSX.IntrinsicElements.h1: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>h1>{
const post: {
    title: string;
}
post
.title: stringtitle}</React.JSX.IntrinsicElements.h1: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>h1>;
} <const Suspense: React.ExoticComponent<React.SuspenseProps>Suspense React.SuspenseProps.fallback?: React.ReactNodefallback={<function Spinner(): React.ReactNodeSpinner />}> <
function Post(props: {
    post: QueryPromise<{
        title: string;
    }>;
}): React.JSX.Element
Post
post: QueryPromise<{
    title: string;
}>
post
={
const loaderData: {
    post: QueryPromise<{
        id: string;
        title: string;
        author: string | null;
        createdAt: string;
    }, ClientError<TrpcError<"NOT_FOUND", {
        id: string;
    }> | SchemaValidationError<ZodObject<{
        id: ZodString;
    }, $strip>>, JsonForm, "NETWORK_ERROR" | "BAD_RESPONSE" | "STREAM_INTERRUPTED">>;
}
loaderData
.
post: QueryPromise<{
    id: string;
    title: string;
    author: string | null;
    createdAt: string;
}, ClientError<TrpcError<"NOT_FOUND", {
    id: string;
}> | SchemaValidationError<ZodObject<{
    id: ZodString;
}, $strip>>, JsonForm, "NETWORK_ERROR" | "BAD_RESPONSE" | "STREAM_INTERRUPTED">>
post
} />
</const Suspense: React.ExoticComponent<React.SuspenseProps>Suspense>;

useQuery finds the cache through the promise, so there is no provider.

Stable promises

Built in, not a link. use() needs the same promise across renders, and these are:

  • One promise per query (path and input, with object keys sorted) while it loads, so calls in flight share one request.
  • The same promise while the data doesn't change. A new one only when it does: a refetch with new data, or setData.
  • Settled promises carry status and value, so use() renders cached data without suspending.

useQuery(promise) returns the query's current promise and re-renders when it changes. useQueryState(promise) gives isFetching, isStale, error, updatedAt and refetch(), for spinners and retry buttons.

Without links, the cache does the least: an entry lives while a request is in flight or a mounted useQuery reads it. Everything else is a link, opt-in one by one:

LinkDoesIn standardLinks()
cacheLink({ staleTime, gcTime })Keeps unread entries gcTime (5 minutes); fresh data (staleTime, 0) makes no requestyes
structuralSharingLink()Refetched data keeps unchanged parts, and unchanged data keeps its promise (no re-render)yes
refetchOnMountLink()A mount on stale data refetches it, except right after the loader's own requestyes
refetchOnWindowFocusLink()Refetches stale, mounted queries when the page is visible againyes
refetchOnReconnectLink()The same when the browser comes back onlineyes
retryLink() (core)Retries failed queries 3 timesyes
invalidateOnMutationLink()After a mutation, invalidates queries and resolves once the mounted ones have refetchedyes

standardLinks() matches TanStack Query's defaults, plus one: like a router after an action, every mutation invalidates queries (all of them, unless invalidates narrows it). Stale data is returned at once and refetched in the background.

Query links are tRPC links: they sit in the same links array, before the link that sends. Write your own with withQueryFeature(link, feature).

Cache methods

await 
const trpc: ReactClient<TrpcClient<{
    post: {
        rename: Procedure<{
            type: "mutation";
            ctx: Context;
            meta: {};
            input: {
                id: string;
                title: string;
            };
            output: Post | undefined;
            errors: SchemaValidationError<z.ZodObject<{
                id: z.ZodString;
                title: z.ZodString;
            }, z.core.$strip>>;
            services: never;
        }>;
        byId: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: {
                id: string;
            };
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }> | SchemaValidationError<z.ZodObject<{
                id: z.ZodString;
            }, z.core.$strip>>;
            services: never;
        }>;
        list: Procedure<...>;
        create: Procedure<...>;
    };
}, {}, undefined, LinksTypes<...>>>
trpc
.
post: ReactProcedures<ClientRouter<{
    rename: Procedure<{
        type: "mutation";
        ctx: Context;
        meta: {};
        input: {
            id: string;
            title: string;
        };
        output: Post | undefined;
        errors: SchemaValidationError<z.ZodObject<{
            id: z.ZodString;
            title: z.ZodString;
        }, z.core.$strip>>;
        services: never;
    }>;
    byId: Procedure<{
        type: "query";
        ctx: Context;
        meta: {};
        input: {
            id: string;
        };
        output: Post;
        errors: TrpcError<"NOT_FOUND", {
            id: string;
        }> | SchemaValidationError<z.ZodObject<{
            id: z.ZodString;
        }, z.core.$strip>>;
        services: never;
    }>;
    list: Procedure<...>;
    create: Procedure<...>;
}, {}, undefined, LinksTypes<...>>>
post
.
byId: DecorateQuery<[input: {
    id: string;
}, opts?: CallOptions<{}> | undefined], {
    ...;
}, ClientError<...>>
byId
.
DecorateQuery<[input: { id: string; }, opts?: CallOptions<{}> | undefined], { id: string; title: string; author: string | null; createdAt: string; }, ClientError<TrpcError<"NOT_FOUND", { id: string; }> | SchemaValidationError<...>, JsonForm, "NETWORK_ERROR" | ... 1 more ... | "STREAM_INTERRUPTED">>.invalidate(input?: {
    id: string;
} | undefined): Promise<void>
invalidate
({ id: stringid }); // refetches it if it's on screen
await
const trpc: ReactClient<TrpcClient<{
    post: {
        rename: Procedure<{
            type: "mutation";
            ctx: Context;
            meta: {};
            input: {
                id: string;
                title: string;
            };
            output: Post | undefined;
            errors: SchemaValidationError<z.ZodObject<{
                id: z.ZodString;
                title: z.ZodString;
            }, z.core.$strip>>;
            services: never;
        }>;
        byId: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: {
                id: string;
            };
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }> | SchemaValidationError<z.ZodObject<{
                id: z.ZodString;
            }, z.core.$strip>>;
            services: never;
        }>;
        list: Procedure<...>;
        create: Procedure<...>;
    };
}, {}, undefined, LinksTypes<...>>>
trpc
.function invalidate(filter?: QueryFilter): Promise<void>invalidate('post'); // every query under post.*
const trpc: ReactClient<TrpcClient<{
    post: {
        rename: Procedure<{
            type: "mutation";
            ctx: Context;
            meta: {};
            input: {
                id: string;
                title: string;
            };
            output: Post | undefined;
            errors: SchemaValidationError<z.ZodObject<{
                id: z.ZodString;
                title: z.ZodString;
            }, z.core.$strip>>;
            services: never;
        }>;
        byId: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: {
                id: string;
            };
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }> | SchemaValidationError<z.ZodObject<{
                id: z.ZodString;
            }, z.core.$strip>>;
            services: never;
        }>;
        list: Procedure<...>;
        create: Procedure<...>;
    };
}, {}, undefined, LinksTypes<...>>>
trpc
.
post: ReactProcedures<ClientRouter<{
    rename: Procedure<{
        type: "mutation";
        ctx: Context;
        meta: {};
        input: {
            id: string;
            title: string;
        };
        output: Post | undefined;
        errors: SchemaValidationError<z.ZodObject<{
            id: z.ZodString;
            title: z.ZodString;
        }, z.core.$strip>>;
        services: never;
    }>;
    byId: Procedure<{
        type: "query";
        ctx: Context;
        meta: {};
        input: {
            id: string;
        };
        output: Post;
        errors: TrpcError<"NOT_FOUND", {
            id: string;
        }> | SchemaValidationError<z.ZodObject<{
            id: z.ZodString;
        }, z.core.$strip>>;
        services: never;
    }>;
    list: Procedure<...>;
    create: Procedure<...>;
}, {}, undefined, LinksTypes<...>>>
post
.
byId: DecorateQuery<[input: {
    id: string;
}, opts?: CallOptions<{}> | undefined], {
    ...;
}, ClientError<...>>
byId
.
DecorateQuery<[input: { id: string; }, opts?: CallOptions<{}> | undefined], { id: string; title: string; author: string | null; createdAt: string; }, ClientError<TrpcError<"NOT_FOUND", { id: string; }> | SchemaValidationError<...>, JsonForm, "NETWORK_ERROR" | ... 1 more ... | "STREAM_INTERRUPTED">>.setData(input: {
    id: string;
}, updater: {
    id: string;
    title: string;
    author: string | null;
    createdAt: string;
} | ((prev: {
    id: string;
    title: string;
    author: string | null;
    createdAt: string;
} | undefined) => {
    id: string;
    title: string;
    author: string | null;
    createdAt: string;
})): void
setData
({ id: stringid }, (
prev: {
    ...;
} | undefined
prev
) => ({ ...
prev: {
    ...;
} | undefined
prev
!, title: stringtitle }));
const trpc: ReactClient<TrpcClient<{
    post: {
        rename: Procedure<{
            type: "mutation";
            ctx: Context;
            meta: {};
            input: {
                id: string;
                title: string;
            };
            output: Post | undefined;
            errors: SchemaValidationError<z.ZodObject<{
                id: z.ZodString;
                title: z.ZodString;
            }, z.core.$strip>>;
            services: never;
        }>;
        byId: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: {
                id: string;
            };
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }> | SchemaValidationError<z.ZodObject<{
                id: z.ZodString;
            }, z.core.$strip>>;
            services: never;
        }>;
        list: Procedure<...>;
        create: Procedure<...>;
    };
}, {}, undefined, LinksTypes<...>>>
trpc
.
post: ReactProcedures<ClientRouter<{
    rename: Procedure<{
        type: "mutation";
        ctx: Context;
        meta: {};
        input: {
            id: string;
            title: string;
        };
        output: Post | undefined;
        errors: SchemaValidationError<z.ZodObject<{
            id: z.ZodString;
            title: z.ZodString;
        }, z.core.$strip>>;
        services: never;
    }>;
    byId: Procedure<{
        type: "query";
        ctx: Context;
        meta: {};
        input: {
            id: string;
        };
        output: Post;
        errors: TrpcError<"NOT_FOUND", {
            id: string;
        }> | SchemaValidationError<z.ZodObject<{
            id: z.ZodString;
        }, z.core.$strip>>;
        services: never;
    }>;
    list: Procedure<...>;
    create: Procedure<...>;
}, {}, undefined, LinksTypes<...>>>
post
.
byId: DecorateQuery<[input: {
    id: string;
}, opts?: CallOptions<{}> | undefined], {
    ...;
}, ClientError<...>>
byId
.
DecorateQuery<[input: { id: string; }, opts?: CallOptions<{}> | undefined], { id: string; title: string; author: string | null; createdAt: string; }, ClientError<TrpcError<"NOT_FOUND", { id: string; }> | SchemaValidationError<...>, JsonForm, "NETWORK_ERROR" | ... 1 more ... | "STREAM_INTERRUPTED">>.getData(input_0: {
    id: string;
}): {
    id: string;
    title: string;
    author: string | null;
    createdAt: string;
} | undefined
getData
({ id: stringid });
await
const trpc: ReactClient<TrpcClient<{
    post: {
        rename: Procedure<{
            type: "mutation";
            ctx: Context;
            meta: {};
            input: {
                id: string;
                title: string;
            };
            output: Post | undefined;
            errors: SchemaValidationError<z.ZodObject<{
                id: z.ZodString;
                title: z.ZodString;
            }, z.core.$strip>>;
            services: never;
        }>;
        byId: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: {
                id: string;
            };
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }> | SchemaValidationError<z.ZodObject<{
                id: z.ZodString;
            }, z.core.$strip>>;
            services: never;
        }>;
        list: Procedure<...>;
        create: Procedure<...>;
    };
}, {}, undefined, LinksTypes<...>>>
trpc
.
post: ReactProcedures<ClientRouter<{
    rename: Procedure<{
        type: "mutation";
        ctx: Context;
        meta: {};
        input: {
            id: string;
            title: string;
        };
        output: Post | undefined;
        errors: SchemaValidationError<z.ZodObject<{
            id: z.ZodString;
            title: z.ZodString;
        }, z.core.$strip>>;
        services: never;
    }>;
    byId: Procedure<{
        type: "query";
        ctx: Context;
        meta: {};
        input: {
            id: string;
        };
        output: Post;
        errors: TrpcError<"NOT_FOUND", {
            id: string;
        }> | SchemaValidationError<z.ZodObject<{
            id: z.ZodString;
        }, z.core.$strip>>;
        services: never;
    }>;
    list: Procedure<...>;
    create: Procedure<...>;
}, {}, undefined, LinksTypes<...>>>
post
.
rename: {
    mutate(input: {
        id: string;
        title: string;
    }, opts?: CallOptions<{}> | undefined): TrpcPromise<{
        id: string;
        title: string;
        author: string | null;
        createdAt: string;
    } | undefined, CallError<{
        type: "mutation";
        ctx: Context;
        meta: {};
        input: {
            id: string;
            title: string;
        };
        output: Post | undefined;
        errors: SchemaValidationError<z.ZodObject<{
            id: z.ZodString;
            title: z.ZodString;
        }, z.core.$strip>>;
        services: never;
    }, JsonForm, LinksTypes<readonly [TrpcLink<{
        form: JsonForm;
        provides: "response";
        builtinErrors: "NETWORK_ERROR" | "BAD_RESPONSE" | "STREAM_INTERRUPTED";
    }, any>]>>>;
}
rename
.
function mutate(input: {
    id: string;
    title: string;
}, opts?: CallOptions<{}> | undefined): TrpcPromise<{
    id: string;
    title: string;
    author: string | null;
    createdAt: string;
} | undefined, CallError<{
    type: "mutation";
    ctx: Context;
    meta: {};
    input: {
        id: string;
        title: string;
    };
    output: Post | undefined;
    errors: SchemaValidationError<z.ZodObject<{
        id: z.ZodString;
        title: z.ZodString;
    }, z.core.$strip>>;
    services: never;
}, JsonForm, LinksTypes<readonly [TrpcLink<{
    form: JsonForm;
    provides: "response";
    builtinErrors: "NETWORK_ERROR" | "BAD_RESPONSE" | "STREAM_INTERRUPTED";
}, any>]>>>
mutate
({ id: stringid, title: stringtitle }); // mutations and subscriptions are the plain client's

Server rendering

On the server, create one client per request (isServer defaults to typeof window === 'undefined'; a server's cache never drops entries). After the render, dehydrate(trpc) encodes the settled queries with the links' serializer, so Dates survive with danSON; hydrate(trpc, state) writes them into the browser's client before it renders.

const const state: DehydratedQueriesstate = function dehydrate(trpc: HasStore, opts?: HydrationOptions): DehydratedQueriesdehydrate(
const serverTrpc: ReactClient<TrpcClient<{
    post: {
        byId: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: {
                id: string;
            };
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }> | SchemaValidationError<ZodObject<{
                id: ZodString;
            }, $strip>>;
            services: never;
        }>;
        list: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: undefined;
            output: Post[];
            errors: never;
            services: never;
        }>;
        create: Procedure<{
            type: "mutation";
            ctx: Context;
            meta: {};
            input: {
                title: string;
            };
            output: Post;
            errors: TrpcError<...> | SchemaValidationError<...>;
            services: never;
        }>;
    };
}, {}, undefined, LinksTypes<...>>>
serverTrpc
); // send it with the HTML
function hydrate(trpc: HasStore, state: DehydratedQueries, opts?: HydrationOptions): voidhydrate(
const trpc: ReactClient<TrpcClient<{
    post: {
        byId: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: {
                id: string;
            };
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }> | SchemaValidationError<ZodObject<{
                id: ZodString;
            }, $strip>>;
            services: never;
        }>;
        list: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: undefined;
            output: Post[];
            errors: never;
            services: never;
        }>;
        create: Procedure<{
            type: "mutation";
            ctx: Context;
            meta: {};
            input: {
                title: string;
            };
            output: Post;
            errors: TrpcError<...> | SchemaValidationError<...>;
            services: never;
        }>;
    };
}, {}, undefined, LinksTypes<...>>>
trpc
, const state: DehydratedQueriesstate); // in the browser, before hydrateRoot