Modern full-stack React framework with SSR, streaming, server functions, and API routes powered by TanStack Router and Vite.
—
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.
The main client-side React component that handles hydration and router initialization for client-side rendering.
/**
* Client-side root component for hydrating the application
* Automatically handles router hydration and initial render
* @returns JSX.Element - The hydrated client application
*/
function StartClient(): JSX.Element;Usage Examples:
import { StrictMode, startTransition } from "react";
import { hydrateRoot } from "react-dom/client";
import { StartClient } from "@tanstack/react-start/client";
// Basic client hydration
startTransition(() => {
hydrateRoot(
document,
<StrictMode>
<StartClient />
</StrictMode>
);
});
// Custom root element hydration
const rootElement = document.getElementById("app");
if (rootElement) {
hydrateRoot(rootElement, <StartClient />);
}The main server-side React component that provides the router for server-side rendering.
/**
* Server-side root component for SSR
* @param props - Configuration object with router instance
* @returns JSX.Element - The server-rendered application
*/
function StartServer<TRouter extends AnyRouter>(props: {
router: TRouter;
}): JSX.Element;
interface AnyRouter {
// Router instance from TanStack Router
state: RouterState;
options: RouterOptions;
history: RouterHistory;
}Usage Examples:
import { StartServer } from "@tanstack/react-start/server";
import { createRouter } from "@tanstack/react-router";
// Create router instance
const router = createRouter({
routeTree: rootRoute,
context: {
// Server context
}
});
// Server-side rendering
function renderApp() {
return <StartServer router={router} />;
}
// In server handler
export default {
fetch: async (request) => {
const html = ReactDOMServer.renderToString(<StartServer router={router} />);
return new Response(html, {
headers: { "content-type": "text/html" }
});
}
};Creates a request handler for the server that processes incoming requests and renders the application.
/**
* Creates the main request handler for server-side processing
* @param streamHandler - Optional custom streaming handler
* @returns RequestHandler for processing HTTP requests
*/
function createStartHandler(
streamHandler?: StreamHandler
): RequestHandler<Register>;
interface RequestHandler<TRegister> {
(request: Request): Promise<Response>;
router?: AnyRouter;
}
interface StreamHandler {
(renderOptions: RenderOptions): ReadableStream | Promise<ReadableStream>;
}
interface RenderOptions {
router: AnyRouter;
request: Request;
responseHeaders: Headers;
}Usage Examples:
import {
createStartHandler,
defaultStreamHandler
} from "@tanstack/react-start/server";
// Basic server handler
const handler = createStartHandler();
export default {
fetch: handler
};
// Custom streaming handler
const customHandler = createStartHandler((options) => {
// Custom streaming logic
return new ReadableStream({
start(controller) {
// Custom rendering logic
const html = renderToString(<StartServer router={options.router} />);
controller.enqueue(new TextEncoder().encode(html));
controller.close();
}
});
});
// Advanced server setup
const handler = createStartHandler(defaultStreamHandler);
export default {
fetch: async (request, env) => {
// Add custom headers or processing
const response = await handler(request);
response.headers.set("X-Powered-By", "TanStack Start");
return response;
}
};Provides the default streaming implementation for server-side rendering with proper error handling and response streaming.
/**
* Default streaming handler for SSR with error handling
* @returns StreamHandler that processes render options and returns a stream
*/
function defaultStreamHandler(): StreamHandler;Usage Examples:
import {
createStartHandler,
defaultStreamHandler
} from "@tanstack/react-start/server";
// Use default streaming
const handler = createStartHandler(defaultStreamHandler());
// Extend default streaming
const extendedHandler = createStartHandler(
async (options) => {
console.log(`Rendering ${options.request.url}`);
return await defaultStreamHandler()(options);
}
);Provides the default rendering implementation for server-side rendering without streaming.
/**
* Default render handler for non-streaming SSR
* @returns RenderHandler that processes render options and returns HTML
*/
function defaultRenderHandler(): RenderHandler;
interface RenderHandler {
(renderOptions: RenderOptions): string | Promise<string>;
}Usage Examples:
import { defaultRenderHandler } from "@tanstack/react-start/server";
// Custom non-streaming handler
const renderHandler = defaultRenderHandler();
async function customRenderToString(options) {
const html = await renderHandler(options);
return `<!DOCTYPE html><html><body>${html}</body></html>`;
}Additional server-side utilities for advanced SSR scenarios.
/**
* Attach server-side SSR utilities to a router instance
* @param router - The router to enhance with SSR capabilities
* @returns Enhanced router with SSR utilities
*/
function attachRouterServerSsrUtils<T extends AnyRouter>(
router: T
): T & ServerSsrUtils;
/**
* Create a generic request handler with custom configuration
* @param options - Handler configuration options
* @returns Configured request handler
*/
function createRequestHandler<T>(
options: RequestHandlerOptions<T>
): RequestHandler<T>;
/**
* Define a handler callback for custom server processing
* @param callback - The handler callback function
* @returns Configured handler callback
*/
function defineHandlerCallback<T>(
callback: HandlerCallback<T>
): HandlerCallback<T>;
/**
* Transform a ReadableStream with router context
* @param stream - The stream to transform
* @param router - Router instance for context
* @returns Transformed stream with router utilities
*/
function transformReadableStreamWithRouter(
stream: ReadableStream,
router: AnyRouter
): ReadableStream;
/**
* Transform a pipeable stream with router context
* @param stream - The pipeable stream to transform
* @param router - Router instance for context
* @returns Transformed pipeable stream
*/
function transformPipeableStreamWithRouter(
stream: any, // React's PipeableStream type
router: AnyRouter
): any;Functions for handling client-side hydration and startup processes.
/**
* Perform client-side hydration of the application
* @returns Promise resolving to the hydrated router instance
*/
function hydrateStart(): Promise<AnyRouter>;
/**
* Render React Server Components on the client
* @param components - RSC components to render
* @returns Rendered RSC content
*/
function renderRsc(components: any): any;import {
createStartHandler,
defaultStreamHandler
} from "@tanstack/react-start/server";
const handler = createStartHandler(defaultStreamHandler());
export default {
fetch: async (request) => {
// Add CORS headers
if (request.method === "OPTIONS") {
return new Response(null, {
status: 204,
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE",
"Access-Control-Allow-Headers": "Content-Type, Authorization"
}
});
}
const response = await handler(request);
// Add security headers
response.headers.set("X-Frame-Options", "DENY");
response.headers.set("X-Content-Type-Options", "nosniff");
return response;
}
};import { createStartHandler } from "@tanstack/react-start/server";
import { renderToPipeableStream } from "react-dom/server";
const customStreamHandler = (options) => {
return new ReadableStream({
start(controller) {
const stream = renderToPipeableStream(
<StartServer router={options.router} />,
{
onShellReady() {
controller.enqueue(new TextEncoder().encode("<!DOCTYPE html>"));
stream.pipe(new WritableStream({
write(chunk) {
controller.enqueue(chunk);
},
close() {
controller.close();
}
}));
},
onError(error) {
console.error("Stream error:", error);
controller.error(error);
}
}
);
}
});
};
const handler = createStartHandler(customStreamHandler);// Router types from TanStack Router
interface AnyRouter {
state: RouterState;
options: RouterOptions;
history: RouterHistory;
navigate: (options: any) => Promise<void>;
resolveRedirect: (redirect: any) => any;
}
// Request handler types
interface RequestHandler<TRegister> {
(request: Request): Promise<Response>;
router?: AnyRouter;
}
interface RequestOptions {
request: Request;
responseHeaders?: Headers;
context?: any;
}
// Streaming types
interface StreamHandler {
(renderOptions: RenderOptions): ReadableStream | Promise<ReadableStream>;
}
interface RenderHandler {
(renderOptions: RenderOptions): string | Promise<string>;
}
interface RenderOptions {
router: AnyRouter;
request: Request;
responseHeaders: Headers;
context?: any;
}
// Server utilities types
interface ServerSsrUtils {
dehydrate: () => DehydratedRouter;
serialize: (data: any) => string;
deserialize: (data: string) => any;
}
interface HandlerCallback<T> {
(context: T): Response | Promise<Response>;
}
interface RequestHandlerOptions<T> {
createRouter: () => AnyRouter;
getRouterContext?: (request: Request) => T;
onError?: (error: Error) => Response;
}
// Dehydrated state for SSR
interface DehydratedRouter {
state: Record<string, any>;
manifest: Record<string, any>;
context?: any;
}// HTTP headers used by the SSR system
const HEADERS: {
readonly contentType: "Content-Type";
readonly location: "Location";
readonly cacheControl: "Cache-Control";
};Install with Tessl CLI
npx tessl i tessl/npm-tanstack--react-start