0
# Server-Side Rendering (SSR)
1
2
Advanced SSR capabilities with automatic query prefetching, cache dehydration/hydration, and response meta handling for Next.js Pages Router.
3
4
## Capabilities
5
6
### ssrPrepass Function
7
8
Built-in SSR prepass implementation that automatically prefetches queries during server-side rendering.
9
10
```typescript { .api }
11
/**
12
* Built-in SSR prepass implementation for automatic query prefetching
13
* Handles server-side rendering with query cache dehydration and hydration
14
* @param opts - Configuration object with parent options, components, and prepass helper
15
*/
16
export const ssrPrepass: TRPCPrepassHelper;
17
18
type TRPCPrepassHelper = (opts: {
19
parent: WithTRPCSSROptions<AnyRouter>;
20
WithTRPC: NextComponentType<any, any, any>;
21
AppOrPage: NextComponentType<any, any, any>;
22
}) => void;
23
```
24
25
**Usage Examples:**
26
27
```typescript
28
import { withTRPC } from "@trpc/next";
29
import { httpBatchLink } from "@trpc/client";
30
import { ssrPrepass } from "@trpc/next/ssrPrepass";
31
import type { AppRouter } from "../pages/api/[trpc]";
32
33
const MyApp = ({ Component, pageProps }) => {
34
return <Component {...pageProps} />;
35
};
36
37
export default withTRPC<AppRouter>({
38
config({ ctx }) {
39
return {
40
links: [
41
httpBatchLink({
42
url: "/api/trpc",
43
headers: ctx?.req?.headers,
44
}),
45
],
46
};
47
},
48
ssr: true,
49
ssrPrepass, // Use the built-in prepass implementation
50
})(MyApp);
51
```
52
53
### SSR Configuration Options
54
55
#### SSR Enablement
56
57
Configure when SSR should be enabled for your application.
58
59
```typescript { .api }
60
interface WithTRPCSSROptions<TRouter extends AnyRouter> {
61
/** Enable SSR with optional conditional function */
62
ssr: true | ((opts: { ctx: NextPageContext }) => boolean | Promise<boolean>);
63
}
64
```
65
66
**Usage Examples:**
67
68
```typescript
69
// Always enable SSR
70
const alwaysSSR = {
71
ssr: true,
72
ssrPrepass,
73
config() { /* ... */ }
74
};
75
76
// Conditional SSR based on route
77
const conditionalSSR = {
78
ssr: ({ ctx }) => {
79
// Only SSR for dashboard pages
80
return ctx.pathname?.startsWith("/dashboard") ?? false;
81
},
82
ssrPrepass,
83
config() { /* ... */ }
84
};
85
86
// Async conditional SSR
87
const asyncConditionalSSR = {
88
ssr: async ({ ctx }) => {
89
// Check user agent or other async conditions
90
const userAgent = ctx.req?.headers["user-agent"];
91
return !userAgent?.includes("bot");
92
},
93
ssrPrepass,
94
config() { /* ... */ }
95
};
96
```
97
98
#### Response Meta Handling
99
100
Configure HTTP response status codes and headers based on tRPC errors and application state.
101
102
```typescript { .api }
103
interface WithTRPCSSROptions<TRouter extends AnyRouter> {
104
/** Function to set response meta like headers and status codes */
105
responseMeta?: (opts: {
106
ctx: NextPageContext;
107
clientErrors: TRPCClientError<TRouter>[];
108
}) => ResponseMeta;
109
}
110
111
interface ResponseMeta {
112
status?: number;
113
headers?: Record<string, string>;
114
}
115
```
116
117
**Usage Examples:**
118
119
```typescript
120
const withResponseMeta = {
121
ssr: true,
122
ssrPrepass,
123
config() { /* ... */ },
124
responseMeta({ ctx, clientErrors }) {
125
const firstError = clientErrors[0];
126
127
if (firstError) {
128
// Set appropriate HTTP status based on tRPC error
129
switch (firstError.data?.code) {
130
case "UNAUTHORIZED":
131
return { status: 401 };
132
case "FORBIDDEN":
133
return { status: 403 };
134
case "NOT_FOUND":
135
return { status: 404 };
136
case "INTERNAL_SERVER_ERROR":
137
return { status: 500 };
138
default:
139
return { status: 400 };
140
}
141
}
142
143
// Set security headers
144
return {
145
headers: {
146
"X-Frame-Options": "DENY",
147
"X-Content-Type-Options": "nosniff",
148
},
149
};
150
},
151
};
152
```
153
154
### SSR Context and Props
155
156
#### TRPCPrepassProps
157
158
Props passed to components during the SSR prepass phase.
159
160
```typescript { .api }
161
interface TRPCPrepassProps<TRouter extends AnyRouter, TSSRContext extends NextPageContext = NextPageContext> {
162
/** tRPC client configuration used during prepass */
163
config: WithTRPCConfig<TRouter>;
164
/** React Query client instance */
165
queryClient: QueryClient;
166
/** tRPC client instance for making requests */
167
trpcClient: TRPCUntypedClient<TRouter> | TRPCClient<TRouter>;
168
/** Current SSR state indicator */
169
ssrState: 'prepass';
170
/** Next.js page context during SSR */
171
ssrContext: TSSRContext;
172
}
173
```
174
175
### Custom SSR Prepass Implementation
176
177
For advanced use cases, you can implement custom SSR prepass logic.
178
179
```typescript
180
// Custom prepass example
181
const customPrepass: TRPCPrepassHelper = ({ parent, WithTRPC, AppOrPage }) => {
182
WithTRPC.getInitialProps = async (appOrPageCtx) => {
183
const ctx = appOrPageCtx.ctx;
184
185
// Your custom SSR logic here
186
const config = parent.config({ ctx });
187
const queryClient = getQueryClient(config);
188
const trpcClient = createTRPCUntypedClient(config);
189
190
// Manually prefetch specific queries
191
await queryClient.prefetchQuery({
192
queryKey: ["user", "profile"],
193
queryFn: () => trpcClient.user.getProfile.query(),
194
});
195
196
// Dehydrate and return state
197
const dehydratedState = dehydrate(queryClient);
198
return {
199
pageProps: {
200
trpcState: transformer.input.serialize(dehydratedState),
201
},
202
};
203
};
204
};
205
```
206
207
### SSR Best Practices
208
209
#### Headers and Cookies
210
211
Pass request headers and cookies to maintain session state during SSR.
212
213
```typescript
214
import { httpBatchLink } from "@trpc/client";
215
216
const ssrConfig = {
217
config({ ctx }) {
218
return {
219
links: [
220
httpBatchLink({
221
url: "/api/trpc",
222
headers: {
223
// Forward all request headers
224
...ctx?.req?.headers,
225
// Or specific headers
226
cookie: ctx?.req?.headers?.cookie,
227
authorization: ctx?.req?.headers?.authorization,
228
},
229
}),
230
],
231
};
232
},
233
ssr: true,
234
ssrPrepass,
235
};
236
```
237
238
#### Error Boundaries
239
240
Handle SSR errors gracefully to prevent complete page failures.
241
242
```typescript
243
const robustSSRConfig = {
244
config() { /* ... */ },
245
ssr: async ({ ctx }) => {
246
try {
247
// Check if SSR is appropriate
248
return ctx.pathname !== "/client-only-page";
249
} catch (error) {
250
// Fall back to client-side rendering on error
251
console.error("SSR check failed:", error);
252
return false;
253
}
254
},
255
responseMeta({ clientErrors }) {
256
// Don't fail the entire page for client errors
257
if (clientErrors.length > 0) {
258
console.error("Client errors during SSR:", clientErrors);
259
}
260
return {};
261
},
262
ssrPrepass,
263
};
264
```
265
266
## Types
267
268
```typescript { .api }
269
// Next.js page context type
270
interface NextPageContext {
271
req?: IncomingMessage;
272
res?: ServerResponse;
273
pathname: string;
274
query: ParsedUrlQuery;
275
asPath?: string;
276
locale?: string;
277
locales?: string[];
278
defaultLocale?: string;
279
}
280
281
// tRPC configuration with SSR support
282
interface WithTRPCConfig<TRouter extends AnyRouter> extends CreateTRPCClientOptions<TRouter>, CreateTRPCReactQueryClientConfig {
283
abortOnUnmount?: boolean;
284
}
285
286
// tRPC client error type
287
interface TRPCClientError<TRouter extends AnyRouter> extends Error {
288
data?: {
289
code: string;
290
httpStatus?: number;
291
};
292
shape?: any;
293
}
294
```