0
# SSR Components
1
2
SSR (Server-Side Rendering) components provide the foundation for rendering React applications on both server and client sides. These components handle hydration, streaming, and the coordination between server and client rendering processes.
3
4
## Capabilities
5
6
### StartClient Component
7
8
The main client-side React component that handles hydration and router initialization for client-side rendering.
9
10
```typescript { .api }
11
/**
12
* Client-side root component for hydrating the application
13
* Automatically handles router hydration and initial render
14
* @returns JSX.Element - The hydrated client application
15
*/
16
function StartClient(): JSX.Element;
17
```
18
19
**Usage Examples:**
20
21
```typescript
22
import { StrictMode, startTransition } from "react";
23
import { hydrateRoot } from "react-dom/client";
24
import { StartClient } from "@tanstack/react-start/client";
25
26
// Basic client hydration
27
startTransition(() => {
28
hydrateRoot(
29
document,
30
<StrictMode>
31
<StartClient />
32
</StrictMode>
33
);
34
});
35
36
// Custom root element hydration
37
const rootElement = document.getElementById("app");
38
if (rootElement) {
39
hydrateRoot(rootElement, <StartClient />);
40
}
41
```
42
43
### StartServer Component
44
45
The main server-side React component that provides the router for server-side rendering.
46
47
```typescript { .api }
48
/**
49
* Server-side root component for SSR
50
* @param props - Configuration object with router instance
51
* @returns JSX.Element - The server-rendered application
52
*/
53
function StartServer<TRouter extends AnyRouter>(props: {
54
router: TRouter;
55
}): JSX.Element;
56
57
interface AnyRouter {
58
// Router instance from TanStack Router
59
state: RouterState;
60
options: RouterOptions;
61
history: RouterHistory;
62
}
63
```
64
65
**Usage Examples:**
66
67
```typescript
68
import { StartServer } from "@tanstack/react-start/server";
69
import { createRouter } from "@tanstack/react-router";
70
71
// Create router instance
72
const router = createRouter({
73
routeTree: rootRoute,
74
context: {
75
// Server context
76
}
77
});
78
79
// Server-side rendering
80
function renderApp() {
81
return <StartServer router={router} />;
82
}
83
84
// In server handler
85
export default {
86
fetch: async (request) => {
87
const html = ReactDOMServer.renderToString(<StartServer router={router} />);
88
return new Response(html, {
89
headers: { "content-type": "text/html" }
90
});
91
}
92
};
93
```
94
95
### Create Start Handler
96
97
Creates a request handler for the server that processes incoming requests and renders the application.
98
99
```typescript { .api }
100
/**
101
* Creates the main request handler for server-side processing
102
* @param streamHandler - Optional custom streaming handler
103
* @returns RequestHandler for processing HTTP requests
104
*/
105
function createStartHandler(
106
streamHandler?: StreamHandler
107
): RequestHandler<Register>;
108
109
interface RequestHandler<TRegister> {
110
(request: Request): Promise<Response>;
111
router?: AnyRouter;
112
}
113
114
interface StreamHandler {
115
(renderOptions: RenderOptions): ReadableStream | Promise<ReadableStream>;
116
}
117
118
interface RenderOptions {
119
router: AnyRouter;
120
request: Request;
121
responseHeaders: Headers;
122
}
123
```
124
125
**Usage Examples:**
126
127
```typescript
128
import {
129
createStartHandler,
130
defaultStreamHandler
131
} from "@tanstack/react-start/server";
132
133
// Basic server handler
134
const handler = createStartHandler();
135
136
export default {
137
fetch: handler
138
};
139
140
// Custom streaming handler
141
const customHandler = createStartHandler((options) => {
142
// Custom streaming logic
143
return new ReadableStream({
144
start(controller) {
145
// Custom rendering logic
146
const html = renderToString(<StartServer router={options.router} />);
147
controller.enqueue(new TextEncoder().encode(html));
148
controller.close();
149
}
150
});
151
});
152
153
// Advanced server setup
154
const handler = createStartHandler(defaultStreamHandler);
155
156
export default {
157
fetch: async (request, env) => {
158
// Add custom headers or processing
159
const response = await handler(request);
160
response.headers.set("X-Powered-By", "TanStack Start");
161
return response;
162
}
163
};
164
```
165
166
### Default Stream Handler
167
168
Provides the default streaming implementation for server-side rendering with proper error handling and response streaming.
169
170
```typescript { .api }
171
/**
172
* Default streaming handler for SSR with error handling
173
* @returns StreamHandler that processes render options and returns a stream
174
*/
175
function defaultStreamHandler(): StreamHandler;
176
```
177
178
**Usage Examples:**
179
180
```typescript
181
import {
182
createStartHandler,
183
defaultStreamHandler
184
} from "@tanstack/react-start/server";
185
186
// Use default streaming
187
const handler = createStartHandler(defaultStreamHandler());
188
189
// Extend default streaming
190
const extendedHandler = createStartHandler(
191
async (options) => {
192
console.log(`Rendering ${options.request.url}`);
193
return await defaultStreamHandler()(options);
194
}
195
);
196
```
197
198
### Default Render Handler
199
200
Provides the default rendering implementation for server-side rendering without streaming.
201
202
```typescript { .api }
203
/**
204
* Default render handler for non-streaming SSR
205
* @returns RenderHandler that processes render options and returns HTML
206
*/
207
function defaultRenderHandler(): RenderHandler;
208
209
interface RenderHandler {
210
(renderOptions: RenderOptions): string | Promise<string>;
211
}
212
```
213
214
**Usage Examples:**
215
216
```typescript
217
import { defaultRenderHandler } from "@tanstack/react-start/server";
218
219
// Custom non-streaming handler
220
const renderHandler = defaultRenderHandler();
221
222
async function customRenderToString(options) {
223
const html = await renderHandler(options);
224
return `<!DOCTYPE html><html><body>${html}</body></html>`;
225
}
226
```
227
228
### Server Utilities
229
230
Additional server-side utilities for advanced SSR scenarios.
231
232
```typescript { .api }
233
/**
234
* Attach server-side SSR utilities to a router instance
235
* @param router - The router to enhance with SSR capabilities
236
* @returns Enhanced router with SSR utilities
237
*/
238
function attachRouterServerSsrUtils<T extends AnyRouter>(
239
router: T
240
): T & ServerSsrUtils;
241
242
/**
243
* Create a generic request handler with custom configuration
244
* @param options - Handler configuration options
245
* @returns Configured request handler
246
*/
247
function createRequestHandler<T>(
248
options: RequestHandlerOptions<T>
249
): RequestHandler<T>;
250
251
/**
252
* Define a handler callback for custom server processing
253
* @param callback - The handler callback function
254
* @returns Configured handler callback
255
*/
256
function defineHandlerCallback<T>(
257
callback: HandlerCallback<T>
258
): HandlerCallback<T>;
259
260
/**
261
* Transform a ReadableStream with router context
262
* @param stream - The stream to transform
263
* @param router - Router instance for context
264
* @returns Transformed stream with router utilities
265
*/
266
function transformReadableStreamWithRouter(
267
stream: ReadableStream,
268
router: AnyRouter
269
): ReadableStream;
270
271
/**
272
* Transform a pipeable stream with router context
273
* @param stream - The pipeable stream to transform
274
* @param router - Router instance for context
275
* @returns Transformed pipeable stream
276
*/
277
function transformPipeableStreamWithRouter(
278
stream: any, // React's PipeableStream type
279
router: AnyRouter
280
): any;
281
```
282
283
### Client Hydration
284
285
Functions for handling client-side hydration and startup processes.
286
287
```typescript { .api }
288
/**
289
* Perform client-side hydration of the application
290
* @returns Promise resolving to the hydrated router instance
291
*/
292
function hydrateStart(): Promise<AnyRouter>;
293
294
/**
295
* Render React Server Components on the client
296
* @param components - RSC components to render
297
* @returns Rendered RSC content
298
*/
299
function renderRsc(components: any): any;
300
```
301
302
## Advanced Usage Patterns
303
304
### Custom Server Handler with Middleware
305
306
```typescript
307
import {
308
createStartHandler,
309
defaultStreamHandler
310
} from "@tanstack/react-start/server";
311
312
const handler = createStartHandler(defaultStreamHandler());
313
314
export default {
315
fetch: async (request) => {
316
// Add CORS headers
317
if (request.method === "OPTIONS") {
318
return new Response(null, {
319
status: 204,
320
headers: {
321
"Access-Control-Allow-Origin": "*",
322
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE",
323
"Access-Control-Allow-Headers": "Content-Type, Authorization"
324
}
325
});
326
}
327
328
const response = await handler(request);
329
330
// Add security headers
331
response.headers.set("X-Frame-Options", "DENY");
332
response.headers.set("X-Content-Type-Options", "nosniff");
333
334
return response;
335
}
336
};
337
```
338
339
### Custom Streaming Implementation
340
341
```typescript
342
import { createStartHandler } from "@tanstack/react-start/server";
343
import { renderToPipeableStream } from "react-dom/server";
344
345
const customStreamHandler = (options) => {
346
return new ReadableStream({
347
start(controller) {
348
const stream = renderToPipeableStream(
349
<StartServer router={options.router} />,
350
{
351
onShellReady() {
352
controller.enqueue(new TextEncoder().encode("<!DOCTYPE html>"));
353
stream.pipe(new WritableStream({
354
write(chunk) {
355
controller.enqueue(chunk);
356
},
357
close() {
358
controller.close();
359
}
360
}));
361
},
362
onError(error) {
363
console.error("Stream error:", error);
364
controller.error(error);
365
}
366
}
367
);
368
}
369
});
370
};
371
372
const handler = createStartHandler(customStreamHandler);
373
```
374
375
## Types
376
377
```typescript { .api }
378
// Router types from TanStack Router
379
interface AnyRouter {
380
state: RouterState;
381
options: RouterOptions;
382
history: RouterHistory;
383
navigate: (options: any) => Promise<void>;
384
resolveRedirect: (redirect: any) => any;
385
}
386
387
// Request handler types
388
interface RequestHandler<TRegister> {
389
(request: Request): Promise<Response>;
390
router?: AnyRouter;
391
}
392
393
interface RequestOptions {
394
request: Request;
395
responseHeaders?: Headers;
396
context?: any;
397
}
398
399
// Streaming types
400
interface StreamHandler {
401
(renderOptions: RenderOptions): ReadableStream | Promise<ReadableStream>;
402
}
403
404
interface RenderHandler {
405
(renderOptions: RenderOptions): string | Promise<string>;
406
}
407
408
interface RenderOptions {
409
router: AnyRouter;
410
request: Request;
411
responseHeaders: Headers;
412
context?: any;
413
}
414
415
// Server utilities types
416
interface ServerSsrUtils {
417
dehydrate: () => DehydratedRouter;
418
serialize: (data: any) => string;
419
deserialize: (data: string) => any;
420
}
421
422
interface HandlerCallback<T> {
423
(context: T): Response | Promise<Response>;
424
}
425
426
interface RequestHandlerOptions<T> {
427
createRouter: () => AnyRouter;
428
getRouterContext?: (request: Request) => T;
429
onError?: (error: Error) => Response;
430
}
431
432
// Dehydrated state for SSR
433
interface DehydratedRouter {
434
state: Record<string, any>;
435
manifest: Record<string, any>;
436
context?: any;
437
}
438
```
439
440
## Constants
441
442
```typescript { .api }
443
// HTTP headers used by the SSR system
444
const HEADERS: {
445
readonly contentType: "Content-Type";
446
readonly location: "Location";
447
readonly cacheControl: "Cache-Control";
448
};
449
```