Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion docs/start/framework/react/guide/middleware.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ export const Route = createFileRoute('/foo')({
You can pass middleware to specific server route methods by using the `createHandlers` utility and passing a middleware array to the `middleware` property of the method object.

```tsx
import { createMiddleware } from '@tanstack/react-start'

const loggingMiddleware = createMiddleware().server(() => {
//...
})
Expand Down Expand Up @@ -324,6 +326,8 @@ const loggingMiddleware = createMiddleware({ type: 'function' })
**Client context is NOT sent to the server by default since this could end up unintentionally sending large payloads to the server.** If you need to send client context to the server, you must call the `next` function with a `sendContext` property and object to transmit any data to the server. Any properties passed to `sendContext` will be merged, serialized and sent to the server along with the data and will be available on the normal context object of any nested server middleware.

```tsx
import { createMiddleware } from '@tanstack/react-start'

const requestLogger = createMiddleware({ type: 'function' })
.client(async ({ next, context }) => {
return next({
Expand All @@ -345,6 +349,7 @@ const requestLogger = createMiddleware({ type: 'function' })
You may have noticed that in the example above that while client-sent context is type-safe, it is is not required to be validated at runtime. If you pass dynamic user-generated data via context, that could pose a security concern, so **if you are sending dynamic data from the client to the server via context, you should validate it in the server-side middleware before using it.**

```tsx
import { createMiddleware } from '@tanstack/react-start'
import { zodValidator } from '@tanstack/zod-adapter'
import { z } from 'zod'

Expand Down Expand Up @@ -372,6 +377,8 @@ Similar to sending client context to the server, you can also send server contex
> The return type of `next` in `client` can only be inferred from middleware known in the current middleware chain. Therefore the most accurate return type of `next` is in middleware at the end of the middleware chain

```tsx
import { createMiddleware } from '@tanstack/react-start'

const serverTimer = createMiddleware({ type: 'function' }).server(
async ({ next }) => {
return next({
Expand Down Expand Up @@ -407,7 +414,7 @@ To have a middleware run for **every request handled by Start**, create a `src/s

```tsx
// src/start.ts
import { createStart } from '@tanstack/react-start'
import { createStart, createMiddleware } from '@tanstack/react-start'

const myGlobalMiddleware = createMiddleware().server(() => {
//...
Expand Down Expand Up @@ -452,6 +459,8 @@ Middleware is executed dependency-first, starting with global middleware, follow
- `fn`

```tsx
import { createMiddleware, createServerFn } from '@tanstack/react-start'

const globalMiddleware1 = createMiddleware({ type: 'function' }).server(
async ({ next }) => {
console.log('globalMiddleware1')
Expand Down Expand Up @@ -513,6 +522,7 @@ Middleware that uses the `client` method executes in a **completely different cl
You can add headers to the outgoing request by passing a `headers` object to `next`:

```tsx
import { createMiddleware } from '@tanstack/react-start'
import { getToken } from 'my-auth-library'

const authMiddleware = createMiddleware({ type: 'function' }).client(
Expand All @@ -531,6 +541,8 @@ const authMiddleware = createMiddleware({ type: 'function' }).client(
When multiple middlewares set headers, they are **merged together**. Later middlewares can add new headers or override headers set by earlier middlewares:

```tsx
import { createMiddleware } from '@tanstack/react-start'

const firstMiddleware = createMiddleware({ type: 'function' }).client(
async ({ next }) => {
return next({
Expand Down Expand Up @@ -588,6 +600,7 @@ For advanced use cases, you can provide a custom `fetch` implementation to contr
**Via Client Middleware:**

```tsx
import { createMiddleware } from '@tanstack/react-start'
import type { CustomFetch } from '@tanstack/react-start'

const customFetchMiddleware = createMiddleware({ type: 'function' }).client(
Expand Down Expand Up @@ -638,6 +651,9 @@ When custom fetch implementations are provided at multiple levels, the following
**Key principle:** The call site always wins. This allows you to override middleware behavior for specific calls when needed.

```tsx
import { createMiddleware, createServerFn } from '@tanstack/react-start'
import type { CustomFetch } from '@tanstack/react-start'

// Middleware sets a fetch that adds logging
const loggingMiddleware = createMiddleware({ type: 'function' }).client(
async ({ next }) => {
Expand Down Expand Up @@ -671,6 +687,9 @@ await myServerFn({ fetch: testFetch }) // Uses testFetch, NOT loggingFetch
When multiple middlewares provide fetch, the last one wins:

```tsx
import { createMiddleware, createServerFn } from '@tanstack/react-start'
import type { CustomFetch } from '@tanstack/react-start'

const firstMiddleware = createMiddleware({ type: 'function' }).client(
async ({ next }) => {
const firstFetch: CustomFetch = (url, init) => {
Expand Down
Loading