or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

hook-creation.mdindex.mdmutation-hooks.mdquery-hooks.mdquery-keys.mdquery-utilities.mdreact-server-components.mdserver-side-helpers.mdsubscription-hooks.md

react-server-components.mddocs/

0

# React Server Components (RSC)

1

2

React Server Components support for tRPC with hydration helpers designed for Next.js App Router and similar frameworks that support RSC.

3

4

## Capabilities

5

6

### createHydrationHelpers

7

8

Creates utilities for prefetching data in React Server Components and hydrating the client with that data.

9

10

```typescript { .api }

11

/**

12

* Creates hydration helpers for React Server Components

13

* @param caller - Server-side router caller instance

14

* @param getQueryClient - Function that returns the QueryClient instance

15

* @returns Object with trpc proxy and HydrateClient component

16

* @note Requires @tanstack/react-query@^5.49.0

17

* @note Make sure to set serializeData/deserializeData in QueryClient for data transformers

18

*/

19

function createHydrationHelpers<TRouter extends AnyRouter>(

20

caller: Caller<TRouter>,

21

getQueryClient: () => QueryClient

22

): HydrationHelpersResult<TRouter>;

23

24

interface HydrationHelpersResult<TRouter extends AnyRouter> {

25

/** Wrapped router caller with prefetch helpers */

26

trpc: DecoratedCaller<TRouter>;

27

/** Component for hydrating client-side React Query cache */

28

HydrateClient: React.ComponentType<{ children: React.ReactNode }>;

29

}

30

31

type Caller<TRouter extends AnyRouter> = ReturnType<

32

RouterCaller<inferRouterRootTypes<TRouter>, TRouter['_def']['record']>

33

>;

34

35

type DecoratedCaller<TRouter extends AnyRouter> = {

36

// All procedures can be called directly: trpc.user.get("123")

37

// Plus prefetch methods: trpc.user.get.prefetch("123")

38

[K in keyof TRouter]: TRouter[K] extends AnyProcedure

39

? DecorateProcedure<inferRouterRootTypes<TRouter>, TRouter[K]>

40

: DecoratedCaller<TRouter[K]>;

41

};

42

43

interface DecorateProcedure<TRoot extends AnyRootTypes, TProcedure extends AnyProcedure> {

44

(input: inferProcedureInput<TProcedure>): Promise<inferProcedureOutput<TProcedure>>;

45

prefetch: (

46

input: inferProcedureInput<TProcedure>,

47

opts?: TRPCFetchQueryOptions<

48

inferTransformedProcedureOutput<TRoot, TProcedure>,

49

TRPCClientError<TRoot>

50

>

51

) => Promise<void>;

52

prefetchInfinite: (

53

input: inferProcedureInput<TProcedure>,

54

opts?: TRPCFetchInfiniteQueryOptions<

55

inferTransformedProcedureOutput<TRoot, TProcedure>,

56

TRPCClientError<TRoot>

57

>

58

) => Promise<void>;

59

}

60

```

61

62

**Usage Examples:**

63

64

```typescript

65

import { createHydrationHelpers } from "@trpc/react-query/rsc";

66

import { createCaller } from "./server/routers/app";

67

import { getQueryClient } from "./lib/query-client";

68

69

// Create the hydration helpers

70

const { trpc, HydrateClient } = createHydrationHelpers(

71

createCaller({ /* server context */ }),

72

getQueryClient

73

);

74

75

// In an RSC component

76

export default async function PostPage({ params }: { params: { id: string } }) {

77

// Direct call for immediate data

78

const post = await trpc.post.get(params.id);

79

80

// Prefetch related data for client hydration

81

await trpc.post.comments.prefetch({ postId: params.id });

82

83

return (

84

<HydrateClient>

85

<div>

86

<h1>{post.title}</h1>

87

<PostComments postId={params.id} />

88

</div>

89

</HydrateClient>

90

);

91

}

92

```

93

94

### QueryClient Configuration

95

96

For proper data transformer support, configure your QueryClient:

97

98

```typescript

99

import { QueryClient } from "@tanstack/react-query";

100

import { transformer } from "./server/transformer"; // Your data transformer

101

102

export const createQueryClient = () =>

103

new QueryClient({

104

defaultOptions: {

105

dehydrate: {

106

serializeData: transformer.serialize,

107

},

108

hydrate: {

109

deserializeData: transformer.deserialize,

110

},

111

},

112

});

113

```

114

115

### HydrateClient Component

116

117

Automatically handles hydration of prefetched data from server to client.

118

119

```typescript { .api }

120

interface HydrateClientProps {

121

children: React.ReactNode;

122

}

123

124

/**

125

* Component that wraps children with HydrationBoundary to hydrate

126

* server-prefetched data into the client QueryClient

127

*/

128

React.ComponentType<HydrateClientProps>

129

```

130

131

**Features:**

132

133

- **Server-Side Prefetching**: Use `.prefetch()` and `.prefetchInfinite()` methods on procedures

134

- **Automatic Hydration**: `HydrateClient` component handles transferring server data to client

135

- **Direct Calls**: Call procedures directly in RSC for immediate data access

136

- **Type Safety**: Full TypeScript inference from router to RSC helpers

137

- **Data Transformers**: Supports custom data transformers via QueryClient configuration

138

139

## Types

140

141

```typescript { .api }

142

interface TRPCFetchQueryOptions<TQueryFnData, TError> {

143

staleTime?: number;

144

retry?: boolean | number | ((failureCount: number, error: TError) => boolean);

145

retryDelay?: number | ((retryAttempt: number, error: TError) => number);

146

refetchOnMount?: boolean | 'always';

147

refetchOnReconnect?: boolean | 'always';

148

refetchOnWindowFocus?: boolean | 'always';

149

}

150

151

interface TRPCFetchInfiniteQueryOptions<TQueryFnData, TError>

152

extends TRPCFetchQueryOptions<TQueryFnData, TError> {

153

initialPageParam?: unknown;

154

getNextPageParam?: (lastPage: TQueryFnData, allPages: TQueryFnData[], lastPageParam: unknown, allPageParams: unknown[]) => unknown;

155

getPreviousPageParam?: (firstPage: TQueryFnData, allPages: TQueryFnData[], firstPageParam: unknown, allPageParams: unknown[]) => unknown;

156

maxPages?: number;

157

}

158

```