Modern full-stack React framework with SSR, streaming, server functions, and API routes powered by TanStack Router and Vite.
—
The middleware system provides composable functions for server functions to handle validation, authentication, logging, and other cross-cutting concerns. Middleware can be chained together and applied to server functions for enhanced functionality.
Creates middleware that can be applied to server functions for request/response processing.
/**
* Creates middleware with optional configuration
* @param options - Configuration options including middleware type
* @returns CreateMiddlewareResult for chaining additional configuration
*/
function createMiddleware<TType extends MiddlewareType>(
options?: { type?: TType }
): CreateMiddlewareResult<{}, TType>;
interface CreateMiddlewareResult<TRegister, TType> {
/** Add middleware function to the chain */
middleware<T>(middleware: T): CreateMiddlewareResult<TRegister & T, TType>;
/** Add input validation to the middleware */
inputValidator<T>(validator: T): CreateMiddlewareResult<TRegister & T, TType>;
/** Add client-side processing */
client<T>(client: T): CreateMiddlewareResult<TRegister & T, TType>;
/** Add server-side processing */
server<T>(server: T): CreateMiddlewareResult<TRegister & T, TType>;
}
type MiddlewareType = 'request' | 'function';Usage Examples:
import { createMiddleware, createServerFn } from "@tanstack/react-start";
// Authentication middleware
const authMiddleware = createMiddleware()
.server(async (input, { request }) => {
const token = request.headers.get('Authorization');
if (!token) throw new Error('Unauthorized');
const user = await verifyToken(token);
return { ...input, user };
});
// Validation middleware
const validateUserInput = createMiddleware()
.inputValidator((data: unknown) => {
if (!data || typeof data !== 'object') {
throw new Error('Invalid input');
}
return data as { name: string; email: string };
});
// Apply middleware to server function
const createUser = createServerFn({ method: 'POST' })
.middleware(authMiddleware)
.middleware(validateUserInput)
.handler(async ({ name, email, user }) => {
// Handler receives validated input + auth context
return await db.user.create({
data: { name, email, createdBy: user.id }
});
});Middleware specifically designed for server functions with type-safe parameter passing.
interface FunctionMiddleware<TInput, TOutput, TContext = {}> {
(input: TInput, context: FunctionMiddlewareContext<TContext>):
Promise<TOutput> | TOutput;
}
interface FunctionMiddlewareContext<T = {}> {
/** Current request object */
request: Request;
/** Response headers */
headers: Headers;
/** Additional context data */
context: T;
/** Continue to next middleware */
next: () => Promise<any>;
}
interface FunctionMiddlewareOptions<
TRegister,
TResponse,
TMiddlewares,
TInputValidator,
THandler
> {
middleware?: TMiddlewares;
inputValidator?: TInputValidator;
handler?: THandler;
}Usage Examples:
import { createMiddleware } from "@tanstack/react-start";
// Logging middleware
const logMiddleware = createMiddleware()
.server(async (input, { request, next }) => {
console.log(`[${new Date().toISOString()}] ${request.method} ${request.url}`);
const start = Date.now();
const result = await next();
console.log(`Request completed in ${Date.now() - start}ms`);
return result;
});
// Rate limiting middleware
const rateLimitMiddleware = createMiddleware()
.server(async (input, { request, next }) => {
const ip = request.headers.get('x-forwarded-for') || 'unknown';
const key = `rate-limit:${ip}`;
const requests = await redis.incr(key);
if (requests === 1) {
await redis.expire(key, 60); // 1 minute window
}
if (requests > 100) {
throw new Error('Rate limit exceeded');
}
return await next();
});Middleware that operates at the request level before server functions are invoked.
interface RequestMiddleware<TContext = {}> {
(request: Request, context: RequestMiddlewareContext<TContext>):
Promise<Response | void> | Response | void;
}
interface RequestMiddlewareContext<T = {}> {
/** Additional context data */
context: T;
/** Continue to next middleware */
next: () => Promise<Response>;
}
interface RequestMiddlewareOptions<
TRegister,
TMiddlewares,
TServer
> {
type: 'request';
middleware?: TMiddlewares;
server?: TServer;
}Helper functions for working with middleware chains and validation.
/**
* Flattens nested middleware arrays into a single array
* @param middlewares - Array of middleware to flatten
* @returns Flattened middleware array
*/
function flattenMiddlewares(
middlewares: AnyFunctionMiddleware[]
): AnyFunctionMiddleware[];
/**
* Executes a middleware chain
* @param middlewares - The middleware chain to execute
* @param context - The execution context
* @returns Result of middleware execution
*/
function executeMiddleware<T>(
middlewares: AnyFunctionMiddleware[],
context: T
): Promise<T>;
/**
* Apply middleware to a function
* @param middleware - The middleware to apply
* @param fn - The function to wrap with middleware
* @returns Enhanced function with middleware
*/
function applyMiddleware<T>(
middleware: AnyFunctionMiddleware[],
fn: T
): T;
/**
* Execute validation logic
* @param validator - The validator to execute
* @param input - The input to validate
* @returns Validated output
*/
function execValidator<T, U>(
validator: Validator<T, U>,
input: T
): U;interface IntersectAllValidatorInputs<T extends ReadonlyArray<any>> {
// Type helper for combining validator inputs
}
interface IntersectAllValidatorOutputs<T extends ReadonlyArray<any>> {
// Type helper for combining validator outputs
}
interface AssignAllMiddleware<T extends ReadonlyArray<any>> {
// Type helper for combining middleware types
}import { createMiddleware } from "@tanstack/react-start";
const conditionalAuth = createMiddleware()
.server(async (input, { request, next }) => {
const publicPaths = ['/health', '/api/public'];
const path = new URL(request.url).pathname;
if (publicPaths.includes(path)) {
return await next();
}
// Apply authentication for protected paths
const token = request.headers.get('Authorization');
if (!token) throw new Error('Authentication required');
const user = await verifyToken(token);
return { ...input, user };
});import { createMiddleware } from "@tanstack/react-start";
const errorHandlerMiddleware = createMiddleware()
.server(async (input, { next }) => {
try {
return await next();
} catch (error) {
console.error('Server function error:', error);
if (error.message === 'Unauthorized') {
throw new Response('Unauthorized', { status: 401 });
}
throw new Response('Internal Server Error', { status: 500 });
}
});// Middleware type definitions
type MiddlewareType = 'request' | 'function';
interface AnyFunctionMiddleware {
type: 'function';
middleware: (...args: any[]) => any;
}
interface AnyRequestMiddleware {
type: 'request';
middleware: (request: Request, context: any) => any;
}
// Function middleware types
interface FunctionMiddlewareWithTypes<
TRegister,
TResponse,
TMiddlewares,
TInputValidator,
THandler
> {
middleware?: TMiddlewares;
inputValidator?: TInputValidator;
handler?: THandler;
}
interface FunctionMiddlewareValidator<T, U> {
(input: T): U;
}
interface FunctionMiddlewareServer<TInput, TOutput> {
(input: TInput, context: ServerFnCtx): Promise<TOutput> | TOutput;
}
interface FunctionMiddlewareClient<TInput, TOutput> {
(input: TInput): Promise<TOutput> | TOutput;
}
// Request middleware types
interface RequestMiddlewareWithTypes<
TRegister,
TMiddlewares,
TServer
> {
type: 'request';
middleware?: TMiddlewares;
server?: TServer;
}
interface RequestServerFn<T> {
(request: Request, context: T): Promise<Response | void> | Response | void;
}
// Middleware context types
interface FunctionMiddlewareAfterMiddleware<T> {
context: T;
next: () => Promise<any>;
}
interface RequestMiddlewareAfterMiddleware<T> {
context: T;
next: () => Promise<Response>;
}
// Validator types
interface Validator<TInput, TOutput> {
(input: TInput): TOutput;
}
// Context assignment helpers
interface AssignAllClientContextBeforeNext<T extends ReadonlyArray<any>> {
// Type helper for client context assignment
}
interface FunctionClientResultWithContext<T, U> {
result: T;
context: U;
}
interface FunctionServerResultWithContext<T, U> {
result: T;
context: U;
}Install with Tessl CLI
npx tessl i tessl/npm-tanstack--react-start